BZOJ 4025 二分图 分治+并查集
2015-05-12 16:55
357 查看
题目大意:给定一张nn个点的图,有mm条边,TT个时间段,每条边只存在于(st,ed](st,ed]这些时间段,求每个时间段内这个图是否是二分图
分治并查集大法好
定义Solve(x,y,E)Solve(x,y,E)为当前处理的区间为[x,y][x,y],EE为所有存在时间为[x,y][x,y]的子集的边的集合
那么对于EE中的每一条边(u,v)(u,v),讨论:
若当前边的存在时间为[x,y][x,y],则在并查集上判断是否出现奇环
如果出现,[x,y][x,y]内的所有时刻都一定不是二分图,输出答案即可
如果不出现,在并查集中连接(u,v)(u,v)
否则判断存在时间和midmid的关系讨论扔进左区间还是右区间还是都扔进去
并查集不需要可持久化,只需要记录进行过的操作,在回溯的时候复原即可
注意并查集不要写路径压缩,因为路径压缩的优化是均摊的,均摊在分治这种树形结构上使用是无效的,只写按秩合并就行了
时间复杂度O(mlog2n)O(mlog^2n)
然而跑的比O(mlogn)O(mlogn)的LCT还快是什么鬼……
分治并查集大法好
定义Solve(x,y,E)Solve(x,y,E)为当前处理的区间为[x,y][x,y],EE为所有存在时间为[x,y][x,y]的子集的边的集合
那么对于EE中的每一条边(u,v)(u,v),讨论:
若当前边的存在时间为[x,y][x,y],则在并查集上判断是否出现奇环
如果出现,[x,y][x,y]内的所有时刻都一定不是二分图,输出答案即可
如果不出现,在并查集中连接(u,v)(u,v)
否则判断存在时间和midmid的关系讨论扔进左区间还是右区间还是都扔进去
并查集不需要可持久化,只需要记录进行过的操作,在回溯的时候复原即可
注意并查集不要写路径压缩,因为路径压缩的优化是均摊的,均摊在分治这种树形结构上使用是无效的,只写按秩合并就行了
时间复杂度O(mlog2n)O(mlog^2n)
然而跑的比O(mlogn)O(mlogn)的LCT还快是什么鬼……
[code]#include <vector> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 using namespace std; struct edge{ int x,y; int st,ed; edge() {} edge(int _,int __,int ___,int ____): x(_),y(__),st(___),ed(____) {} }; int n,m,T; int stack[M<<2],top; //若x<0 代表x的rank被加了1 //若x>0 表示x的父亲被修改了 namespace Union_Find_Set{ int fa[M],rank[M],a[M]; int Find(int x) { while(fa[x]!=x) x=fa[x]; return fa[x]=x; } int Distance(int x) { int re=0; while(fa[x]!=x&&fa[x]) re^=a[x],x=fa[x]; return re; } void Union(int x,int y,int z) { x=Find(x);y=Find(y); if(x==y) return ; if(rank[x]>rank[y]) swap(x,y); if(rank[x]==rank[y]) rank[y]++,stack[++top]=-y; fa[x]=y;a[x]=z;stack[++top]=x; } void Restore(int bottom) { while(top>bottom) { if(stack[top]<0) rank[-stack[top]]--; else fa[stack[top]]=stack[top],a[stack[top]]=0; top--; } } } void Divid_And_Conquer(int x,int y,vector<edge> &e) { using namespace Union_Find_Set; vector<edge>::iterator it; int i,mid=x+y>>1,bottom=top; vector<edge> l,r; for(it=e.begin();it!=e.end();it++) { if(it->st==x&&it->ed==y) { int _x=Find(it->x); int _y=Find(it->y); int _z=Distance(it->x)^Distance(it->y)^1; if(_x!=_y) Union(_x,_y,_z); else if(_z&1) { for(i=x;i<=y;i++) puts("No"); Restore(bottom); return ; } } else if(it->ed<=mid) l.push_back(*it); else if(it->st>mid) r.push_back(*it); else l.push_back(edge(it->x,it->y,it->st,mid)),r.push_back(edge(it->x,it->y,mid+1,it->ed)); } if(x==y) puts("Yes"); else Divid_And_Conquer(x,mid,l),Divid_And_Conquer(mid+1,y,r); Restore(bottom); } int main() { //freopen("4025.in","r",stdin); //freopen("4025.out","w",stdout); int i; edge e; vector<edge> v; cin>>n>>m>>T; for(i=1;i<=n;i++) Union_Find_Set::fa[i]=i; for(i=1;i<=m;i++) { scanf("%d%d%d%d",&e.x,&e.y,&e.st,&e.ed); e.st++; if(e.st>e.ed) continue; v.push_back(e); } Divid_And_Conquer(1,T,v); return 0; }
相关文章推荐
- BZOJ 4025: 二分图 [线段树CDQ分治 并查集]
- BZOJ 4025 [并查集][二分图][分治]
- [BZOJ4025]二分图(线段树分治,并查集)
- BZOJ 4025|二分图|CDQ分治|并查集|LCT
- [CDQ分治 并查集 || LCT] BZOJ 4025 二分图
- BZOJ_4025_二分图_线段树按时间分治+并查集
- BZOJ 4025: 二分图 并查集判二分图 CDQ分治
- bzoj 4025 二分图 分治+并查集/LCT
- bzoj 4025: 二分图 (分治+图论)
- 4025: 二分图 分治+并查集
- 【bzoj4025】【二分图】【lct】
- bzoj4025 二分图(线段树分治+带权并查集维护路径长奇偶性)
- BZOJ 4025 二分图(时间树+并查集)
- [CDQ分治 并查集] BZOJ 1453 [Wc]Dface双面棋盘
- bzoj4025 二分图(lct)
- BZOJ4025 二分图
- BZOJ4025 二分图(线段树分治+并查集)
- 【BZOJ 4025】 (CDQ?还是整体二分?+并查集及它的恢复操作)
- JZOJ4769 【GDOI2017模拟9.9】graph CDQ分治+用按秩合并维护带撤销的并查集(BZOJ 4025)
- [BZOJ4025][LCT]二分图