首先我们可以把没有询问过的边处理掉,重构图
当然这样也不影响复杂度
考虑到每次询问要删除的边很少,我们完全可以整体处理
把询问划分成两个集合,在前半部分询问未出现边我们可以整体处理掉,缩点重编号(询问的边和点都要重编号)
然后通过分治继续对前半部分做
然后回来,后半部分我们也可以同样的处理
这样我们要维护一个关于当前边集的栈即可
UPD:省队集训的时候听到一种非常神的的随机化做法,摘录如下:
Step1:随便建立一颗生成树;
Step2:对于每一条不在生成树上的边,随机一个64位整数作为这条边的权值;
Step3:对于每条在生成树上的边,定义它的权值为连接他的两个端点对应部分的所有非树边的权值的xor和;
Step4:对于每一组询问,枚举询问中边的子集,如果某个子集所对应的边的权值xor和等于0,则我们可以断言,去掉这些边以后图不连通;否则,去掉这些边不影响图的连通性。
证明我有时间在放上来吧(并不会……),不过很明显这个复杂度随便操cdq分治
type node=record
x,y:longint;
end;
var e:array[..] of node;
te:array[..] of node;
q:array[..,..] of longint;
h,fa:array[..] of longint;
v,ans:array[..] of boolean;
mh:array[..] of longint;
t,tm,th,n,m,k,i,j:longint; function getf(x:longint):longint;
begin
if fa[x]<>x then fa[x]:=getf(fa[x]);
exit(fa[x]);
end; procedure lab(n,m,l,r:longint);
var i,j,x,y:longint;
begin
for i:= to n do
fa[i]:=i;
for i:= to m do
if not v[i] then
begin
x:=getf(e[i].x); y:=getf(e[i].y);
if x<>y then fa[x]:=y;
end;
th:=;
for i:= to n do
if fa[i]=i then
begin
inc(th);
h[i]:=th;
end;
for i:= to n do
h[i]:=h[getf(i)];
tm:=;
for i:= to m do
if v[i] then
begin
inc(tm);
mh[i]:=tm;
e[tm].x:=h[e[i].x];
e[tm].y:=h[e[i].y];
end;
for i:=l to r do
for j:= to q[i,] do
q[i,j]:=mh[q[i,j]];
end; procedure mark(l,r:longint);
var i,j:longint;
begin
for i:=l to r do
for j:= to q[i,] do
v[q[i,j]]:=true;
end; procedure cdq(n,m,l,r:longint);
var mid,i:longint;
begin
if l=r then
begin
ans[l]:=true;
for i:= to q[l,] do
if e[q[l,i]].x<>e[q[l,i]].y then
begin
ans[l]:=false;
break;
end;
exit;
end;
mid:=(l+r) shr ;
for i:= to m do
begin
inc(t);
te[t]:=e[i]; //te维护边的栈
v[i]:=false;
end;
mark(l,mid);
lab(n,m,l,mid);
cdq(th,tm,l,mid);
for i:=m downto do
begin
e[i]:=te[t];
dec(t);
v[i]:=false;
end;
mark(mid+,r);
lab(n,m,mid+,r);
cdq(th,tm,mid+,r);
end; begin
readln(n,m);
for i:= to m do
readln(e[i].x,e[i].y);
readln(k);
for i:= to k do
begin
read(q[i,]);
for j:= to q[i,] do
read(q[i,j]);
readln;
end;
mark(,k);
lab(n,m,,k);
cdq(th,tm,,k);
for i:= to k do
if ans[i] then writeln('Connected')
else writeln('Disconnected');
end.