Ztxz16学图论
题目大意
给定
N
个点,
数据范围
题解
做到这题的时候,我真的是不知所措,不过后面还是想到了一种解法。然而,这题提供的题解,竟是LCT(动态树),表示我这种蒟蒻实在是不会这种高级的做法了。
我们看一下题目,只有询问操作,没有修改操作,可以离线处理,这让我们不禁想到了一种奥妙重重的算法——莫队算法。
然而我们会发现一个残酷的现实,在转移的同时我们需要维护一个并查集,加边容易维护答案,可是删边时难以维护并查集和答案啊!
那这样子是否意味着莫队算法就不能做了呢?
NO
!
注意现在,我们只能使用加边操作,不能使用删边操作,用并查集就可以实现,但如何在不能使用删边操作下维护答案呢?
这个问题是可以解决的。
假设当前的一连串询问左边界L所在块的编号都相同(这里的编号指分块后的编号),此时右坐标
R
是递增,当前这一块的右边界为
然后对于每次询问,我们现时维护并查集
function getfather(o:longint):longint;
begin
if 并查集U[o]尚未从并查集K获取信息 then
begin
U[o]:=K[o];
将点o的状态设为已获取信息;
end;
if U[o]=o then exit(o);//如果是并查集的根,则退出并返回函数值
U[o]:=getfather(U[o]);
exit(U[o]);
end;
像这样维护并查集并同时维护答案即可。
我们分析一下时间复杂度,每一个块的
再看一下
L
,每次询问
总的来说,时间复杂度是
1.5
次的,这十分优秀。
var
f1,f2,ans,ph:array[0..200000] of longint;
cqy,ff,be,en,n,m,q,i,j,k,l,xd,o,p,u:longint;
xw:array[0..200000,1..4] of longint;
bj:array[0..200000,1..2] of longint;
function min(a,b:int64):int64;
begin
if a<b then exit(a)
else exit(b);
end;
procedure sjzl;
var
i,k:longint;
begin
randomize;
for i:=1 to q div 2 do
begin
k:=q div 2+1+random(q div 2);
xw[0]:=xw[i];
xw[i]:=xw[k];
xw[k]:=xw[0];
end;
end;
procedure qsort(l,r:longint);
var
i,j,m,mm:longint;
begin
i:=l;
j:=r;
m:=xw[(l+r) div 2,3];
mm:=xw[(l+r) div 2,2];
repeat
while (xw[i,3]<m) or (xw[i,3]=m) and (xw[i,2]<mm) do inc(i);
while (xw[j,3]>m) or (xw[j,3]=m) and (xw[j,2]>mm) do dec(j);
if i<=j then
begin
xw[0]:=xw[i];
xw[i]:=XW[j];
XW[j]:=xw[0];
inc(i);
dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
function find1(o:longint):longint;
begin
if ph[o]<>xd then
begin
f1[o]:=f2[o];
ph[o]:=xd;
end;
if f1[o]=o then exit(O);
f1[o]:=find1(f1[o]);
exit(f1[o]);
end;
function find2(o:longint):longint;
begin
if f2[o]=o then exit(o);
f2[o]:=find2(f2[o]);
exit(f2[o]);
end;
begin
readln(n,m,q);
for i:=1 to m do
readln(bj[i,1],bj[i,2]);
p:=trunc(sqrt(n));
for i:=1 to q do
begin
read(xw[i,1],xw[i,2]);
xw[i,4]:=i;
xw[i,3]:=xw[i,1] div p;
if xw[i,1] mod p>0 then inc(xw[i,3]);
end;
sjzl;
qsort(1,q);
cqy:=0;
ff:=n;
for i:=1 to q do
begin
if cqy<>xw[i,3] then
begin
cqy:=xw[i,3];
be:=min(n,p*xw[i,3]);
en:=be-1;
ff:=n;
for j:=1 to n do
begin
f1[j]:=j;
f2[j]:=j;
end;
end;
o:=ff;
if xw[i,2]<be then
begin
inc(xd);
for j:=xw[i,1] to xw[i,2] do
if find1(bj[j,1])<>find1(bj[j,2]) then
begin
f1[f1[bj[j,1]]]:=f1[bj[j,2]];
dec(o);
end;
ans[xw[i,4]]:=o;
end
else
begin
for j:=en+1 to xw[i,2] do
if find2(bj[j,1])<>find2(bj[j,2]) then
begin
f2[f2[bj[j,1]]]:=f2[bj[j,2]];
dec(ff);
end;
en:=xw[i,2];
inc(xd);
o:=ff;
for j:=xw[i,1] to be-1 do
if find1(bj[j,1])<>find1(bj[j,2]) then
begin
f1[f1[bj[j,1]]]:=f1[bj[j,2]];
dec(o);
end;
ans[xw[i,4]]:=o;
end;
end;
for i:=1 to q do
writeln(ans[i]);
end.