bzoj 4025 二分图 分治+并查集/LCT
2017-08-16 17:07
337 查看
bzoj 4025 二分图
【题目大意】有n个点m条边,边会在start时刻出现在end时刻消失,求对于每一段时间,该图是不是一个二分图。
判断二分图的一个简单的方法:是否存在奇环
若存在奇环,就不是二分图。
假设加入一条u->v的边,u,v已经联通,怎么知道是否是一个奇环呢?只需要知道u,v之间的距离就行了。距离为偶数则是一个奇环。
路径?加边?删边?
很容易就想到是LCT。
维护u->v的距离。
每次加入一条边,就判断是否先前已经联通,否,则家父,若是,就判断u,v之间的距离。
假若已经构成一个奇环,那么,在这个环的任意一条边都未被删除前,都不是二分图。
那就在维护一个minv,表示最小的end值。加入一条边构成了环,就删掉最小end值的那条边,加入新边。
由于是最小值,删掉不会有影响。(最小的end值的那条边肯定是先消失的)
要把边拆成点,为了记录min值,以及对应的边。
细节,慢慢处理就好了。(被坑了好久……)
注意:有自环,需特判。
【附上代码】#include<cstdio> #include<algorithm> #define imax(a,b) ((a>b)?(a):(b)) #define imin(a,b) ((a<b)?(a):(b)) using namespace std; const int N=100010; int n,m,T,cnt,len; struct tree { tree *c[2],*f,*pp,*L,*R; bool flip; int minv,val,siz; int d() { return (f->c[1]==this); } void sc(tree *x,int d) { (c[d]=x)->f=this; } } nil[N*3],*ro[N*3],*stack[N*3]; struct data { int u,v,start,end; } d[N<<1]; int ans[N]; tree *newtree() { nil[++cnt]=nil[0]; return nil+cnt; } void down(tree *x) { if(x==nil) return; if(x->flip) { x->flip=0; swap(x->c[0],x->c[1]); if(x->c[0]!=nil) x->c[0]->flip^=1; if(x->c[1]!=nil) x->c[1]->flip^=1; } } void up(tree *x) { if(x==nil) return; x->minv=x->val; x->siz=1; if(x->c[0]!=nil) x->minv=imin(x->minv,x->c[0]->minv),x->siz+=x->c[0]->siz; if(x->c[1]!=nil) x->minv=imin(x->minv,x->c[1]->minv),x->siz+=x->c[1]->siz; } void rotate(tree *x) { int d=x->d(); tree *y=x->f; y->sc(x->c[!d],d); if(y->f==nil) x->f=nil; else y->f->sc(x,y->d()); x->sc(y,!d); up(y); up(x); x->pp=y->pp; y->pp=nil; } void splay(tree *x) { int hy=1; stack[hy]=x; for(;stack[hy]->f!=nil;hy++) stack[hy+1]=stack[hy]->f; for(;hy;) down(stack[hy]),hy--; for(tree *y;x->f!=nil;) { y=x->f; if(y->f!=nil) (x->d()^y->d())?rotate(x):rotate(y); rotate(x); } } void access(tree *x) { tree *y=nil; while(x!=nil) { splay(x); if(x->c[1]!=nil) { x->c[1]->f=nil; x->c[1]->pp=x; } x->c[1]=y; if(y!=nil) { y->f=x; y->pp=nil; } up(x); y=x; x=x->pp; } } void evert(tree *x) { access(x); splay(x); x->flip^=1; } void link(tree *x,tree *y) { evert(y); y->pp=x; } void cut(tree *x,tree *y) { evert(x); access(y); splay(y); if(y->c[0]!=nil) { y->c[0]->f=nil; y->c[0]=nil; } up(y); } tree *findroot(tree *x) { access(x); splay(x); while(x->c[0]!=nil) { x=x->c[0]; down(x); } splay(x); return x; } tree *findmin(tree *x,tree *y) { evert(x); access(y); splay(x); down(x); len=(x->siz+1)>>1; int find=x->minv; for(;;) { if(x->val==find) break; if(x->c[0]!=nil && x->c[0]->minv==find) x=x->c[0]; else x=x->c[1]; down(x); } splay(x); return x; } bool cmp(data A,data B) { return (A.start<B.start); } int main() { scanf("%d%d%d",&n,&m,&T); cnt=0; nil->val=nil->minv=1e9; nil->siz=0; nil->pp=nil; nil->f=nil->c[0]=nil->c[1]=nil->L=nil->R=nil; for(int i=1;i<=m;i++) scanf("%d%d%d%d",&d[i].u,&d[i].v,&d[i].start,&d[i].end); sort(d+1,d+1+m,cmp); for(int i=1;i<=n;i++) ro[i]=newtree(); for(int i=1;i<=m;i++) { ro[n+i]=newtree(); ro[n+i]->val=d[i].end; ro[n+i]->minv=d[i].end; ro[n+i]->L=ro[d[i].u]; ro[n+i]->R=ro[d[i].v]; } for(int i=1;i<=m;i++) { if(d[i].u==d[i].v) { ans[d[i].start]++; ans[d[i].end]--; continue; } if(findroot(ro[d[i].u])!=findroot(ro[d[i].v])) { link(ro[d[i].u],ro[n+i]); link(ro[n+i],ro[d[i].v]); } else { tree *getmin=findmin(ro[d[i].u],ro[d[i].v]); if(d[i].start<getmin->val && (len&1)) { ans[d[i].start]++; ans[imin(getmin->val,d[i].end)]--; //重点啊,我就被这里坑了 } if(d[i].end>getmin->val) { cut(getmin,getmin->L); cut(getmin,getmin->R); link(ro[d[i].u],ro[n+i]); link(ro[n+i],ro[d[i].v]); } } } int yu=0; for(int i=0;i<T;i++) { yu+=ans[i]; if(yu>0) printf("No\n"); else printf("Yes\n"); } return 0; }
【其他思路】
分治+可回溯并查集(就是不带路径压缩的并查集)
Solve(L,R,S)表示处理L到R这个时间段,有关联的边集为S。
如果存在L->R的时间段的边,且加入后构成了奇环,那么L->R这段时间都不为二分图,直接退出。
把边集划分为左右两边,即边与左区间的交集归左边,右边的交集归右边。(是start和end的交集)
然后先处理左边,再处理右边就行了。
具体的看这里,我没写cdq分治,这是我同学的
相关文章推荐
- BZOJ 4025 二分图 分治+并查集
- BZOJ 4025: 二分图 [线段树CDQ分治 并查集]
- BZOJ_4025_二分图_线段树按时间分治+并查集
- BZOJ 4025 [并查集][二分图][分治]
- BZOJ 4025|二分图|CDQ分治|并查集|LCT
- [CDQ分治 并查集 || LCT] BZOJ 4025 二分图
- [BZOJ4025]二分图(线段树分治,并查集)
- bzoj 4025: 二分图 (分治+图论)
- bzoj4025 二分图(线段树分治+带权并查集维护路径长奇偶性)
- BZOJ4025 : 二分图
- bzoj4025 二分图
- [bzoj4025]二分图
- 【BZOJ4025】二分图 LCT
- bzoj4025 二分图
- bzoj 4025: 二分图(可撤销并查集+CDQ分治)
- bzoj 4025: 二分图 cdq分治+并查集
- [BZOJ4025]二分图(lct)
- BZOJ 4025: 二分图
- bzoj4025 二分图
- BZOJ4025 二分图(线段树分治+并查集)