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; }