Description
Input
Output
Sample Input
4 5
1 2
2 3
3 4
4 1
2 4
3
1 5
2 2 3
2 1 2
Sample Output
Connected
Disconnected
Connected
HINT
N<=100000N<=100000 M<=200000M<=200000 K<=100000K<=100000
Source
思路
cdq分治,用并查集维护图,首先将任何询问都没有涉及到的边都添加到并查集中;
对于分治的一个区间的询问:
1. 首先将右区间有左区间没有的边添加到并查集中;
2. 递归处理左区间;
3. 还原并查集到递归这个区间的初始状态;
4. 将左区间有右区间没有的边添加到并查集中;
5. 递归处理右区间;
6. 同3
并查集可以用按秩合并。
代码
#include <cstdio>
const int maxn=100000;
const int maxm=1000000;
template<typename t>
struct stack
{
t s[maxn+10];
int head;
inline int push(t x)
{
s[++head]=x;
return 0;
}
inline int pop()
{
--head;
return 0;
}
inline t top()
{
return s[head];
}
inline int size()
{
return head;
}
};
struct data
{
int num,pr,t;
};
inline data make_data(int num_,int pr_,int t_)
{
data res;
res.num=num_;
res.pr=pr_;
res.t=t_;
return res;
}
int n,tt;
struct union_find_set
{
int fa[maxn+10],h[maxn+10],cnt;
stack<data> st;
inline int find(int x)
{
return fa[x]?find(fa[x]):x;
}
inline int merge(int x,int y,int kind,int ti)
{
x=find(x);
y=find(y);
if(x==y)
{
return 1;
}
--cnt;
if(h[x]>h[y])
{
fa[y]=x;
if(kind)
{
st.push(make_data(y,h[x],ti));
}
}
else
{
fa[x]=y;
if(kind)
{
st.push(make_data(x,h[y],ti));
}
if(h[x]==h[y])
{
++h[y];
}
}
return 0;
}
inline int split(int ti)
{
while(st.size())
{
data d=st.top();
if(d.t!=ti)
{
return 0;
}
st.pop();
h[fa[d.num]]=d.pr;
fa[d.num]=0;
++cnt;
}
return 0;
}
};
union_find_set s;
int m,k,c[maxm+10],q[maxm+10][4],line[maxm+10][2],ans[maxm+10];
int tmp[maxm+10];
int solve(int l,int r)
{
if(l==r)
{
if(s.cnt==1)
{
ans[l]=0;
}
else
{
ans[l]=1;
}
return 0;
}
++tt;
int mid=(l+r)>>1;
for(register int i=mid+1; i<=r; ++i)
{
for(register int j=0; j<c[i]; ++j)
{
tmp[q[i][j]]=1;
}
}
for(register int i=l; i<=mid; ++i)
{
for(register int j=0; j<c[i]; ++j)
{
tmp[q[i][j]]=0;
}
}
for(register int i=mid+1; i<=r; ++i)
{
for(register int j=0; j<c[i]; ++j)
{
if(tmp[q[i][j]]==1)
{
s.merge(line[q[i][j]][0],line[q[i][j]][1],1,tt);
}
}
}
solve(l,mid);
s.split(tt);
for(register int i=l; i<=mid; ++i)
{
for(register int j=0; j<c[i]; ++j)
{
tmp[q[i][j]]=1;
}
}
for(register int i=mid+1; i<=r; ++i)
{
for(register int j=0; j<c[i]; ++j)
{
tmp[q[i][j]]=0;
}
}
for(register int i=l; i<=mid; ++i)
{
for(register int j=0; j<c[i]; ++j)
{
if(tmp[q[i][j]]==1)
{
s.merge(line[q[i][j]][0],line[q[i][j]][1],1,tt);
}
}
}
solve(mid+1,r);
s.split(tt);
for(register int i=l; i<=mid; ++i)
{
for(register int j=0; j<c[i]; ++j)
{
tmp[q[i][j]]=0;
}
}
--tt;
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
for(register int i=1; i<=m; ++i)
{
scanf("%d%d",&line[i][0],&line[i][1]);
}
scanf("%d",&k);
for(register int i=1; i<=k; ++i)
{
scanf("%d",&c[i]);
for(register int j=0; j<c[i]; ++j)
{
scanf("%d",&q[i][j]);
}
}
s.cnt=n;
for(register int i=1; i<=n; ++i)
{
s.h[i]=1;
}
for(register int i=1; i<=k; ++i)
{
for(register int j=0; j<c[i]; ++j)
{
tmp[q[i][j]]=1;
}
}
for(register int i=1; i<=m; ++i)
{
if(!tmp[i])
{
s.merge(line[i][0],line[i][1],0,0);
}
}
for(register int i=1; i<=k; ++i)
{
for(register int j=0; j<c[i]; ++j)
{
tmp[q[i][j]]=0;
}
}
solve(1,k);
for(register int i=1; i<=k; ++i)
{
if(ans[i])
{
puts("Disconnected");
}
else
{
puts("Connected");
}
}
return 0;
}