[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.
相关文章推荐
- 【服务器】CentOS下部署运行NodeJs Web App
- Java中print、printf、println的区别
- 延时跳转Activity
- js判断json是否存在某个字段
- js判断json是否存在某个字段
- codeforces 631B (STL set)
- 1039. Course List for Student (25)
- IOS屏幕的适配
- NYOJ+一笔画问题+先要判断无向图的连通性(DFS or并查集),然后使用欧拉回路。
- openwrt看IP流量
- 近来的思考
- Java编程思想重点笔记
- 十进制转化十六进制
- javascript的事件
- dos攻击
- codeforces2016
- OSChina 周日乱弹 ——程序员怎么攒钱买房子!(励志、温情)
- 替换空格
- 服务降级
- 设置/取消 IE代理