[CDQ分治 并查集 || LCT] BZOJ 4025 二分图

Po姐的姿势:http://blog.csdn.net/popoqqq/article/details/45671813


LCT的做法:

考虑随便维护一个图的生成树,不难发现,如果一条边加入后,形成奇环的话就不是二分图

否则的话,我们可以无视这条边,因为如果之后再新加入一条边和这条边形成了一个奇环

那么新加入的边一定和原来生成树上的边也能形成奇环

所以我们直接维护一棵生成树即可

然后裸的想法就来了:上lct,维护以离开时间为边权的最大生成树,每次加边弹出环上最早离开的边


分治 并查集:

定义 Solve(x,y,E) 为当前处理的区间为 [x,y] E 为所有存在时间为 [x,y] 的子集的边的集合 
那么对于 E 中的每一条边 (u,v) ,讨论: 
若当前边的存在时间为 [x,y] ,则在并查集上判断是否出现奇环 
如果出现, [x,y] 内的所有时刻都一定不是二分图,输出答案即可 
如果不出现,在并查集中连接 (u,v)  
否则判断存在时间和 mid 的关系讨论扔进左区间还是右区间还是都扔进去 


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
using namespace std;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=200005;

struct edge{
	int x,y,l,r;
	edge(int x,int y,int l,int r):x(x),y(y),l(l),r(r) { }
};

struct Operation{
	int f,x;
	Operation(int f=0,int x=0):f(f),x(x) { }
}Stk[4*N];
int top;

int fat[N],rel[N],rank[N];

inline int Fat(int u){
	while (fat[u]!=u) u=fat[u];
	return u;
}

inline int Rel(int u){
	int ret=0;
	while (fat[u]!=u) ret^=rel[u],u=fat[u];
	return ret;
}

inline void Union(int x,int y,int z){
	if (rank[x]>rank[y]) swap(x,y);
	if (rank[x]==rank[y]) rank[y]++,Stk[++top]=Operation(0,y);
	fat[x]=y; rel[x]=z; Stk[++top]=Operation(1,x);
}

inline void Restore(int bottom){
	while (top>bottom){
		if (Stk[top].f==0)
			rank[Stk[top].x]--;
		else
			fat[Stk[top].x]=Stk[top].x,rel[Stk[top].x]=0;
		top--;
	}
}

typedef vector<edge>::iterator ITER;

void Divi(int l,int r,vector<edge> E){
	int mid=(l+r)>>1,bottom=top;
	vector<edge> L,R;
	for (ITER it=E.begin();it!=E.end();it++)
	{
		if (it->l==l && it->r==r)
		{
			int fx=Fat(it->x),fy=Fat(it->y),z=Rel(it->x)^Rel(it->y)^1;
            if(fx!=fy)
                Union(fx,fy,z);
            else
			{ 
				if(z&1)
        		{
             		for(int i=l;i<=r;i++) printf("No\n");
              		Restore(bottom);
              		return ;
          		}
            }
		}
		else if(it->r<=mid)
            L.push_back(*it);
        else if(it->l>mid)
            R.push_back(*it);
        else
            L.push_back(edge(it->x,it->y,it->l,mid)),R.push_back(edge(it->x,it->y,mid+1,it->r));
	}
	if (l==r) 
		printf("Yes\n");
	else
		Divi(l,mid,L),Divi(mid+1,r,R);
    Restore(bottom);
}

int n,m,T;

int main()
{
	int x,y,l,r;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	vector<edge> e;
	read(n); read(m); read(T);
	for (int i=1;i<=n;i++)
		fat[i]=i;
	for (int i=1;i<=m;i++)
	{
		read(x); read(y); read(l); read(r);
		l++; if (l>r) continue;
		e.push_back(edge(x,y,l,r));
	}
	Divi(1,T,e);
	return 0;
}


你可能感兴趣的:([CDQ分治 并查集 || LCT] BZOJ 4025 二分图)