[BZOJ4025]二分图(线段树分治,并查集)
2018-04-06 10:54
477 查看
4025: 二分图
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 2191 Solved: 800
[Submit][Status][Discuss]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 2Sample Output
Yes
No
YesHINT
样例说明:
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。
Source
[Submit][Status][Discuss]
挺妙的思想,线段树不仅仅是一种数据结构,还是一种处理问题的思想,在图论的建图等方面也有用到。
这个方法全称应该叫“线段树对时间CDQ分治”,用于处理有时间参数的修改与询问问题。但是有一个前提,就是一个时间区间的修改可以分成互不影响的两个时间区间的修改,比如这题的边(u,v,start,end)可以分裂为(u,v,start,mid)和(u,v,mid+1,end)。
这题听说LCT可做,但还有一种思路,CDQ(L,R,A)表示询问在[L,R]中,关于这个询问(且还未被处理)的修改集合为A的分治过程。具体流程是:
1.遍历A,对于所有完全包含[L,R]的修改操作进行处理。
2.将A中所有不完全包含[L,R]的修改操作按照线段树的分法分到包含[L,mid]和[mid+1,R]的两个区间中,用集合B和C记录这些修改。
3.分别递归[L,mid]和[mid+1,R],如果L=R则可以直接特判回溯。
4.撤销本层所有操作,保证后续回溯与递归正确进行。
回到这一题,所谓修改就是记录距离的并查集操作(因为判断二分图的方法就是查找里面是否有奇环),所以这里的并查集必须支持撤销,不能路径压缩。总复杂度$O(n\log^2 n)$
#include<cstdio> #include<vector> #include<algorithm> #define rep(i,l,r) for (int i=l; i<=r; i++) typedef long long ll; using namespace std; const int N=200100; int n,m,T,u,v,l,r,top; struct E{int u,v,l,r; bool operator<(const E &a)const{ return (l==a.l)?r<a.r:l<a.l; } }; vector<E> a; struct P{ int fa,val,sz; }t ; struct D{ int x,y; P a,b; }stk ; void init(){ rep(i,1,n) t[i]=(P){i,0,1}; } int find(int x){ while (t[x].fa!=x) x=t[x].fa; return x;} int dis(int x){ int res=0; while (t[x].fa!=x) res^=t[x].val,x=t[x].fa; return res; } void link(int x,int y){ int val=dis(x)^dis(y)^1; x=find(x); y=find(y); stk[++top]=(D){x,y,t[x],t[y]}; if (t[x].sz>t[y].sz) swap(x,y); t[x].fa=y; t[x].val=val; t[y].sz+=t[x].sz; } void recov(int k){ while (top!=k) t[stk[top].x]=stk[top].a,t[stk[top].y]=stk[top].b,top--; } void CDQ(int L,int R,vector<E> &a){ int mid=(L+R)>>1,bot=top; vector<E> b,c; for (int i=0; i<(int)a.size(); i++){ E now=a[i]; int x=now.u,y=now.v; if (now.l==L && now.r==R){ int p=find(x),q=find(y); if (p==q){ int val=dis(x)^dis(y); if (val==0){ rep(i,L,R) puts("No"); recov(bot); return; } }else link(x,y); }else if (now.r<=mid) b.push_back(now); else if (now.l>mid) c.push_back(now); else b.push_back((E){now.u,now.v,now.l,mid}),c.push_back((E){now.u,now.v,mid+1,now.r}); } if (L==R) puts("Yes"); else CDQ(L,mid,b),CDQ(mid+1,R,c); recov(bot); } int main(){ freopen("bzoj4025.in","r",stdin); freopen("bzoj4025.out","w",stdout); scanf("%d%d%d",&n,&m,&T); rep(i,1,m){ scanf("%d%d%d%d",&u,&v,&l,&r); l++; if (l<=r) a.push_back((E){u,v,l,r}); } init(); CDQ(1,T,a); return 0; }
相关文章推荐
- BZOJ 4025: 二分图 [线段树CDQ分治 并查集]
- BZOJ_4025_二分图_线段树按时间分治+并查集
- BZOJ 4025 [并查集][二分图][分治]
- [CDQ分治 并查集 || LCT] BZOJ 4025 二分图
- BZOJ 4025 二分图 分治+并查集
- BZOJ 4025|二分图|CDQ分治|并查集|LCT
- BZOJ 4025: 二分图 并查集判二分图 CDQ分治
- bzoj 4025 二分图 分治+并查集/LCT
- bzoj4025二分图 线段树分治+并查集
- 4025: 二分图 分治+并查集
- bzoj 4025: 二分图 (分治+图论)
- bzoj4025 二分图
- BZOJ 3674: 可持久化并查集加强版/BZOJ 3673: 可持久化并查集 by zky 可持久化线段树
- BZOJ 3673 可持久化并查集 可持久化线段树
- [玄学分治 || 线段树] BZOJ 2675 Bomb & Tsin 1322 Bomb(李超)
- 【BZOJ3673/3674】可持久化并查集/可持久化并查集加强版 可持久化线段树
- BZOJ 4025: 二分图
- bzoj 2733 永无乡 - 并查集 - 线段树
- bzoj 4025: 二分图 cdq分治+并查集
- 【BZOJ5005】乒乓游戏 [线段树][并查集]