分治到区间 [l,r] 时,将 [mid+1,r] 中不在 [l,mid] 出现的边加入,然后分治左区间,右区间类似。这样就能保证分治到一个区间时所有不在区间中的边都加入了。并查集维护图的连通就好了。
#include<bits/stdc++.h>
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void Read(int& x){
char c=nc();
for(;c<'0'||c>'9';c=nc());
for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());
}
#define N 100010
#define M 200010
int a[N][5],num[N];
int k,n,m,p;
int f[N],s[M*50],t[M*50],top;
int u[M],v[M],Q,c[M];
bool Ans[N];
inline int Find(int x){
if(f[x]==x)return x;
int y=Find(f[x]);
if(y!=f[x])s[++top]=x,t[top]=f[x];
return f[x]=y;
}
inline void Solve(int l,int r){
int k=top;
if(l==r){
bool fl=0;
for(int i=1;i<=num[l];i++){
int tmp=a[l][i];
int x=Find(u[tmp]),y=Find(v[tmp]);
if(x!=y){
fl=1;
break;
}
}
while(top!=k)f[s[top]]=t[top],top--;
Ans[l]=fl;
return;
}
int Mid=l+r>>1;
for(int i=Mid+1;i<=r;i++)
for(int j=1;j<=num[i];j++){
int tmp=a[i][j];
if(!(--c[tmp])){
int x=Find(u[tmp]),y=Find(v[tmp]);
if(x!=y){
s[++top]=x;t[top]=f[x];f[x]=y;
}
}
}
Solve(l,Mid);
for(int i=Mid+1;i<=r;i++)for(int j=1;j<=num[i];j++)c[a[i][j]]++;
while(top!=k)f[s[top]]=t[top],top--;
for(int i=l;i<=Mid;i++)
for(int j=1;j<=num[i];j++){
int tmp=a[i][j];
if(!(--c[tmp])){
int x=Find(u[tmp]),y=Find(v[tmp]);
if(x!=y){
s[++top]=x;t[top]=f[x];f[x]=y;
}
}
}
Solve(Mid+1,r);
for(int i=l;i<=Mid;i++)for(int j=1;j<=num[i];j++)c[a[i][j]]++;
while(top!=k)f[s[top]]=t[top],top--;
}
int main(){
Read(n);Read(m);
for(int i=1;i<=m;i++)Read(u[i]),Read(v[i]);
Read(Q);
for(int i=1;i<=Q;i++){
Read(num[i]);
for(int j=1;j<=num[i];j++)Read(a[i][j]),c[a[i][j]]++;
}
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=m;i++)
if(!c[i]){
int x=Find(u[i]),y=Find(v[i]);
if(x!=y)f[x]=y;
}
Solve(1,Q);
for(int i=1;i<=Q;i++)
if(!Ans[i])puts("Connected");else puts("Disconnected");
return 0;
}