题目链接: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;
}