您的位置:首页 > 其它

[BZOJ3572] [Hnoi2014]世界树

2016-03-05 23:54 316 查看

传送门

http://www.lydsy.com/JudgeOnline/problem.php?id=3572

题目大意

给定一棵树,每次给一些关键点,树上每个点都被离他最近的关键点支配,距离相同取编号小的关键点,每次询问每个关键点支配的点个数

题解

显然虚树(数据范围),主要在统计上

建出虚树后,我们先求出来虚树上的每个点被哪个关键点支配

这个两次DFS统计即可(一次用ii子树中的节点更新ii一次用ii的父节点更新ii)

然后我们统计每个关键点支配个数

虚树上的边(u,v)(u,v)分为

bel[u]=bel[v]bel[u]=bel[v] 边上的点全部计入ans[bel[u]]ans[bel[u]]

bel[u]!=bel[v]bel[u]!=bel[v] 倍增找到分界点加入两边

如果原树上某条路径的两端只有一个在虚树上,我们这么统计

很明显这些点一定是与在虚树上的那一端属于同一个点支配的

定义点uu他的虚树上的儿子son[u]son[u]以及u和son[u]在原树路径上u的儿子节点vu和son[u]在原树路径上u的儿子节点v

那么没被统计的部分就是size[u]−∑size[v]size[u]-\sum size[v]

以上就都统计到了

const
maxn=300050;
inf=1000000000;
var
w:array[0..3*maxn,1..2]of longint;
bel,pos,dep,x,y,ans,t,size,key,cle:array[0..maxn]of longint;
st:array[0..maxn,0..20]of longint;
i,j,k:longint;
n,m,len,a,b,top,cnt,tt:longint;
procedure init(a,b:longint);
begin
w[len,1]:=b; w[len,2]:=0;
if (w[a,2]=0) then w[a,2]:=len else w[w[a,1],2]:=len;
w[a,1]:=len; inc(len);
end;

procedure sort(l,r:longint);
var i,j,a,b:longint;
begin
i:=l; j:=r; a:=pos[x[(l+r)div 2]];
repeat
while (pos[x[i]]<a) do inc(i);
while (a<pos[x[j]]) do dec(j);
if not(i>j) then
begin
b:=x[i]; x[i]:=x[j]; x[j]:=b;
inc(i); dec(j);
end;
until i>j;
if (l<j) then sort(l,j);
if (i<r) then sort(i,r);
end;

procedure dfs(a,fa:longint);
var tt:longint;
begin
tt:=w[a,2]; inc(len); pos[a]:=len; size[a]:=1;
while tt<>0 do
begin
if (w[tt,1]<>fa) then
begin
dep[w[tt,1]]:=dep[a]+1;
st[w[tt,1],0]:=a;
dfs(w[tt,1],a);
inc(size[a],size[w[tt,1]]);
end;
tt:=w[tt,2];
end;
end;

function lca(a,b:longint):longint;
var i:longint;
begin
if (dep[a]<dep[b]) then begin i:=a; a:=b; b:=i; end;
for i:=20 downto 0 do
if (dep[st[a,i]]>=dep[b]) then a:=st[a,i];
if (a=b) then exit(a);
for i:=20 downto 0 do
if (st[a,i]<>st[b,i]) then begin a:=st[a,i]; b:=st[b,i]; end;
exit(st[a,0]);
end;

function get(fa,a:longint):Longint;
var i:longint;
begin
for i:=20 downto 0 do
if (dep[st[a,i]]>dep[fa]) then a:=st[a,i];
exit(a);
end;

function dis(a,b:longint):longint;
begin exit(dep[a]+dep[b]-2*dep[lca(a,b)]); end;

procedure dfs1(a:longint); //用子节点更新父节点的bel值
var tt:longint;
begin
tt:=w[a,2];
if (key[a]=1) then bel[a]:=a else bel[a]:=inf;
while (tt<>0) do
begin
dfs1(w[tt,1]);
if (bel[w[tt,1]]<>inf)and((bel[a]=inf)or(dis(bel[w[tt,1]],a)<dis(bel[a],a))or((dis(bel[w[tt,1]],a)=dis(bel[a],a))and(bel[w[tt,1]]<bel[a])))
then bel[a]:=bel[w[tt,1]];
tt:=w[tt,2];
end;
end;

procedure dfs2(a,fa:longint); //用父节点更新子节点的bel值
var tt:longint;
begin
if (a<>0)and((dis(bel[fa],a)<dis(a,bel[a]))or((dis(bel[fa],a)=dis(a,bel[a]))and(bel[fa]<bel[a])))
then bel[a]:=bel[fa];
tt:=w[a,2];
while (tt<>0) do
begin dfs2(w[tt,1],a); tt:=w[tt,2]; end;
end;

procedure solve(a,fa:longint); //统计贡献
var tt,sum,aa,i:longint;
begin
if (fa=0) then inc(ans[bel[a]],size[1]-size[a])
else
begin
tt:=get(fa,a); aa:=a;
if (bel[a]=bel[fa]) then inc(ans[bel[a]],size[tt]-size[a])
else
begin
for i:=20 downto 0 do
begin
if (dep[st[aa,i]]<dep[tt]) then continue;
if (dis(st[aa,i],bel[a])<dis(st[aa,i],bel[fa]))or((dis(st[aa,i],bel[a])=dis(st[aa,i],bel[fa]))and(bel[a]<bel[fa]))
then aa:=st[aa,i];
end;
inc(ans[bel[a]],size[aa]-size[a]);
inc(ans[bel[fa]],size[tt]-size[aa]);
end;
end;
tt:=w[a,2]; sum:=size[a];
while (tt<>0) do
begin
dec(sum,size[get(a,w[tt,1])]);
solve(w[tt,1],a);
tt:=w[tt,2];
end;
inc(ans[bel[a]],sum);
end;

begin
readln(n); len:=n+1;
for i:=1 to n-1 do
begin readln(a,b); init(a,b); init(b,a); end;
init(0,1); init(1,0);
dep[0]:=1; len:=0; dfs(0,0);
for j:=1 to 20 do
for i:=1 to n do
st[i,j]:=st[st[i,j-1],j-1];
fillchar(key,sizeof(key),0);
fillchar(bel,sizeof(bel),0);
fillchar(ans,sizeof(ans),0);
fillchar(w,sizeof(w),0);
readln(m);
for i:=1 to m do
begin
readln(cnt);
for j:=1 to cnt do
begin read(x[j]); y[j]:=x[j]; cle[j]:=x[j]; key[x[j]]:=1; end;
sort(1,cnt);
top:=1; t[top]:=0; len:=n+1; cle[0]:=cnt+1; cle[cnt+1]:=0;
for j:=1 to cnt do
begin
tt:=lca(x[j],t[top]);
while (dep[tt]<dep[t[top]]) do
begin
if (dep[t[top-1]]<=dep[tt]) then
begin
init(tt,t[top]);
dec(top);
if (t[top]<>tt) then begin inc(top); t[top]:=tt; inc(cle[0]); cle[cle[0]]:=tt; end;
break;
end;
init(t[top-1],t[top]);
dec(top);
end;
inc(top); t[top]:=x[j];
end;
while (top>1) do
begin init(t[top-1],t[top]);
dec(top); end;
dfs1(0);
dfs2(0,0);
solve(w[w[0,2],1],0);
for j:=1 to cnt do write(ans[y[j]],' '); writeln;
for j:=1 to cle[0] do
begin
w[cle[j],2]:=0;
key[cle[j]]:=0;
bel[cle[j]]:=inf;
ans[cle[j]]:=0;
end;
end;
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: