bzoj3237[Ahoi2013] 连通图
题目链接:bzoj3237
题目大意:
给一个N个点M条边的无向图。有K个询问,每个询问描述一个边集,你要输出若该边集从原图中删除,该图还是否连通。
是,则输出Conected;否,则输出Disconnected
题解:
cdq分治+并查集
首先把所有没有影响的边都建出来
分治过程:
1、把左边没有右边有的边建出来
2、分治左边
3、把并查集恢复至初始的样子
4、把右边没有左边有的边建出来
5、分治右边
每次建的边数为这个区间内的集合中的边数,是一个与n无关的量,所以复杂度是正确的
O(qclogqc)
时间戳的思路不错
#cp http://blog.csdn.net/u012288458/article/details/51377391
目测这个大大看的CA爷写的,居然能看懂%%%
判断一个图是否连通,只要看看被删除的边集中一边上的两点是否连通(用并查集判断)就好了。
恢复并查集的话就是在修改前用栈记录,恢复的时候改回来就好了
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define N 100010 #define M 200010 struct node { int x,y,tim; }a[M]; struct ques { int num,c[5]; }q[N]; int tim,tp;bool ans[N]; int fa[N],sta1[N*50],sta2[N*50]; int ffind(int x) { if (fa[x]!=x) { int y=fa[x]; sta1[++tp]=x;sta2[tp]=y; fa[x]=ffind(fa[x]); } return fa[x]; } void solve(int l,int r) { int now=tp,i,j; if (l==r) { bool bk=true; for (i=1;i<=q[l].num;i++) if (ffind(a[q[l].c[i]].x)!=ffind(a[q[l].c[i]].y)) {bk=false;break;} ans[l]=bk; while (tp!=now) fa[sta1[tp]]=sta2[tp],tp--; return; } int mid=(l+r)>>1; tim++; for (i=l;i<=mid;i++) for (j=1;j<=q[i].num;j++) a[q[i].c[j]].tim=tim; for (i=mid+1;i<=r;i++) for (j=1;j<=q[i].num;j++) if (a[q[i].c[j]].tim!=tim) { int f1=ffind(a[q[i].c[j]].x),f2=ffind(a[q[i].c[j]].y); if (f1!=f2) { sta1[++tp]=f1;sta2[tp]=fa[f1]; fa[f1]=f2; } } solve(l,mid); while (tp!=now) fa[sta1[tp]]=sta2[tp],tp--; tim++; for (i=mid+1;i<=r;i++) for (j=1;j<=q[i].num;j++) a[q[i].c[j]].tim=tim; for (i=l;i<=mid;i++) for (j=1;j<=q[i].num;j++) if (a[q[i].c[j]].tim!=tim) { int f1=ffind(a[q[i].c[j]].x),f2=ffind(a[q[i].c[j]].y); if (f1!=f2) { sta1[++tp]=f1;sta2[tp]=fa[f1]; fa[f1]=f2; } } solve(mid+1,r); } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n,m,i,j,k; scanf("%d%d",&n,&m); for (i=1;i<=n;i++) fa[i]=i; for (i=1;i<=m;i++) {scanf("%d%d",&a[i].x,&a[i].y);a[i].tim=0;} scanf("%d",&k); tim=1;tp=0; for (i=1;i<=k;i++) { scanf("%d",&q[i].num); for (j=1;j<=q[i].num;j++) { scanf("%d",&q[i].c[j]); a[q[i].c[j]].tim=tim; } } for (i=1;i<=m;i++) if (a[i].tim!=tim) { int f1=ffind(a[i].x),f2=ffind(a[i].y); if (f1!=f2) fa[f1]=f2; } solve(1,k); for (i=1;i<=k;i++) if (ans[i]) printf("Connected\n");else printf("Disconnected\n"); return 0; }