CF813F Bipartite Checking

一、题目

点此看题

二、解法

把每条边出现时间段打到线段树上面,然后跑一遍线段树。

问题在于维护一个树的结构,如果一条边连接的两点暂时还不连通,我们就连接一波。否则我们看这条非树边构成的环是不是奇环,如果是的话直接不符合条件,否则没有影响(这里你需要考虑两条非树边构成的环)

可以用启发式合并的并查集,可以算一个点到根的距离的奇偶 d i s dis dis,合并 ( u , v ) (u,v) (u,v)需要连接一条 d i s ( u ) ⊕ d i s ( v ) ⊕ 1 dis(u)\oplus dis(v)\oplus 1 dis(u)dis(v)1,因为我们是合并的根,你可以发现这样构建的两点距离是 1 1 1 。回退的时候记录一下哪两个点合并,撤销就很容易了。

#include 
#include 
#include 
#include 
using namespace std;
#define mk make_pair
#define pii pair
const int M = 100005;
int read()
{	
	int x=0,flag=1;char c;
	while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
	while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x*flag;
}
int n,m,tp,dep[M],c[M],fa[M],st[2*M];
map<pii,int> mp;vector<pii> v[4*M];
int find(int x)
{
	return x==fa[x]?x:find(fa[x]);
}
int dis(int x)
{
	return x==fa[x]?0:(c[x]^dis(fa[x]));
}
void merge(int u,int v,int ct)
{
	if(dep[u]<dep[v]) swap(u,v);
	fa[v]=u;c[v]=ct;
	if(dep[u]==dep[v]) st[++tp]=-u,dep[u]++;
	st[++tp]=v;
}
void back(int t)
{
	while(tp>t)
	{
		if(st[tp]<0) dep[-st[tp]]--;
		else fa[st[tp]]=st[tp],c[st[tp]]=0;
		tp--;
	}
}
void ins(int i,int l,int r,int L,int R,pii x)
{
	if(l>R || L>r) return ;
	if(L<=l && r<=R)
	{
		v[i].push_back(x);
		return ;
	}
	int mid=(l+r)>>1;
	ins(i<<1,l,mid,L,R,x);
	ins(i<<1|1,mid+1,r,L,R,x);
}
void ask(int i,int l,int r)
{
	int cur=tp;
	for(int j=0;j<v[i].size();j++)
	{
		int x=v[i][j].first,y=v[i][j].second;
		int flag=dis(x)^dis(y)^1; 
		if(find(x)==find(y))
		{
			if(flag)
			{
				for(int i=l;i<=r;i++)
					puts("NO");
				back(cur);
				return ;
			}
		}
		else merge(find(x),find(y),flag);
	}
	if(l==r)
	{
		puts("YES");
		back(cur);
		return ;
	}
	int mid=(l+r)>>1;
	ask(i<<1,l,mid);
	ask(i<<1|1,mid+1,r);
	back(cur);
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++)
		fa[i]=i;
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read();pii t=mk(u,v);
		if(mp.count(t))
			ins(1,1,m,mp[t],i-1,t),mp.erase(t);
		else mp[t]=i;
	}
	for(map<pii,int>::iterator it=mp.begin();it!=mp.end();it++)
		ins(1,1,m,it->second,m,it->first);
	ask(1,1,m);
}

你可能感兴趣的:(线段树分治,并查集)