【BZOJ4025】二分图 LCT
【BZOJ4025】二分图
Description
神犇有一个n个节点的图。因为神犇是神犇,所以在T时间内一些边会出现后消失。神犇要求出每一时间段内这个图是否是二分图。这么简单的问题神犇当然会做了,于是他想考考你。
Input
输入数据的第一行是三个整数n,m,T。
第2行到第m+1行,每行4个整数u,v,start,end。第i+1行的四个整数表示第i条边连接u,v两个点,这条边在start时刻出现,在第end时刻消失。
Output
输出包含T行。在第i行中,如果第i时间段内这个图是二分图,那么输出“Yes”,否则输出“No”,不含引号。
Sample Input
3 3 3
1 2 0 2
2 3 0 3
1 3 1 2
1 2 0 2
2 3 0 3
1 3 1 2
Sample Output
Yes
No
Yes
No
Yes
HINT
样例说明:
0时刻,出现两条边1-2和2-3。
第1时间段内,这个图是二分图,输出Yes。
1时刻,出现一条边1-3。
第2时间段内,这个图不是二分图,输出No。
2时刻,1-2和1-3两条边消失。
第3时间段内,只有一条边2-3,这个图是二分图,输出Yes。
数据范围:
n<=100000,m<=200000,T<=100000,1<=u,v<=n,0<=start<=end<=T。
题解:感觉cdq分治过于高端,LCT比较好想~
我们希望这样一个集合(本质是数组),保存的是当前时刻,所有加入之后会形成奇环的非树边。如果当前时刻集合中有元素,则不是一个二分图。那么删边的时候如何处理呢?如果我们删的是一条树边,那么假如集合中存在一条覆盖这条树边的非树边,那么这条非树边就会变成新的树边。这样的情况很难处理,所以我们希望保证:所有已经进入集合的非树边都不会从集合中出来再次成为树边,即,我们要维护的是关于删除时间的最大生成树。可以用LCT搞定。
然后就没啦~我在link的时候手残连的是实边,居然也过了~
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn=500010; int n,m,T,tot,sum; int vis[maxn]; struct LCT { int ch[2],fa,v,sm,rev,siz; }s[maxn]; struct edge { int pa,pb,t1,t2; }p[maxn]; struct operate { int tim,op,org; }q[maxn]; bool cmp(operate a,operate b) { return (a.tim==b.tim)?(a.op>b.op):(a.tim<b.tim); } bool isr(int x) {return s[s[x].fa].ch[0]!=x&&s[s[x].fa].ch[1]!=x;} int MN(int a,int b) { return s[a].v<s[b].v?a:b; } void pushup(int x) { s[x].siz=s[s[x].ch[0]].siz+s[s[x].ch[1]].siz+1; s[x].sm=MN(x,MN(s[s[x].ch[0]].sm,s[s[x].ch[1]].sm)); } void pushdown(int x) { if(s[x].rev) { swap(s[x].ch[0],s[x].ch[1]); if(s[x].ch[0]) s[s[x].ch[0]].rev^=1; if(s[x].ch[1]) s[s[x].ch[1]].rev^=1; s[x].rev=0; } } void updata(int x) { if(!isr(x)) updata(s[x].fa); pushdown(x); } void rotate(int x) { int y=s[x].fa,z=s[y].fa,d=(x==s[y].ch[1]); if(!isr(y)) s[z].ch[y==s[z].ch[1]]=x; s[x].fa=z,s[y].fa=x,s[y].ch[d]=s[x].ch[d^1]; if(s[x].ch[d^1]) s[s[x].ch[d^1]].fa=y; s[x].ch[d^1]=y; pushup(y),pushup(x); } void splay(int x) { updata(x); while(!isr(x)) { int y=s[x].fa,z=s[y].fa; if(!isr(y)) { if((x==s[y].ch[1])^(y==s[z].ch[1])) rotate(x); else rotate(y); } rotate(x); } } void access(int x) { for(int y=0;x;splay(x),s[x].ch[1]=y,pushup(x),y=x,x=s[x].fa); } void maker(int x) { access(x),splay(x),s[x].rev^=1; } void link(int x,int y) //x上 { //printf("l %d %d\n",x,y); access(x),splay(x),maker(y); s[x].ch[1]=y,s[y].fa=x,pushup(x); } void cut(int x,int y) { //printf("c %d %d\n",x,y); maker(x),access(y),splay(y); s[y].ch[0]=s[x].fa=0,pushup(y); } int findr(int x) { access(x),splay(x); while(s[x].ch[0]) x=s[x].ch[0]; return x; } int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret*f; } int main() { n=rd(),m=rd(),T=rd(); int i,j,a,b,c,d; for(i=0;i<=n;i++) s[i].v=1<<30; for(i=1;i<=m;i++) { p[i].pa=rd(),p[i].pb=rd(),q[i].tim=p[i].t1=rd(),s[i+n].v=q[i+m].tim=p[i].t2=rd(); s[i+n].siz=1,s[i+n].sm=i+n; q[i].org=q[i+m].org=i,q[i].op=1,q[i+m].op=0; } sort(q+1,q+2*m+1,cmp); for(i=j=1;i<=T;i++) { for(;j<=2*m&&q[j].tim<i;j++) { a=p[q[j].org].pa,b=p[q[j].org].pb,c=q[j].org+n; if(q[j].op) { if(findr(a)!=findr(b)) link(a,c),link(b,c); else { maker(a),access(b),splay(b),d=s[b].sm; if((s[b].siz+1)&2) { sum++; if(s[d].v<s[c].v) cut(d,p[d-n].pa),cut(d,p[d-n].pb),link(a,c),link(b,c),vis[d]=1; else vis[c]=1; } else { if(s[d].v<s[c].v) cut(d,p[d-n].pa),cut(d,p[d-n].pb),link(a,c),link(b,c),vis[d]=2; else vis[c]=2; } } } else { if(!vis[c]) cut(c,a),cut(c,b); if(vis[c]==1) sum--; } } if(sum) printf("No\n"); else printf("Yes\n"); } return 0; }
| 欢迎来原网站坐坐! >原文链接<