题意:有一棵树,树有边权,有若干次询问,给出一些点,求:

1.这些点互相之间的距离之和

2.点对距离中的最大和最小值

n<=1000000

q<=50000并且保证所有k之和<=2*n 
 
思路:感谢Gold_7
建立虚树,在上面树形DP即可
最大值和最小值用了一种精妙的写法来保证是最值+次值
终于会写类似点对距离和的树形DP了
 var head,vet,next,len,
head1,vet1,next1,len1,
h,stk,b,dep,dfn,flag,c:array[..]of longint;
dp:array[..,..]of longint;
size,g:array[..]of int64;
f:array[..,..]of longint;
n,i,tot,que,ans1,ans2,time,x,y:longint;
ans:int64; procedure swap(var x,y:longint);
var t:longint;
begin
t:=x; x:=y; y:=t;
end; function min(x,y:int64):int64;
begin
if x<y then exit(x);
exit(y);
end; function max(x,y:int64):int64;
begin
if x>y then exit(x);
exit(y);
end; procedure add(a,b,c:longint);
begin
inc(tot);
next[tot]:=head[a];
vet[tot]:=b;
len[tot]:=c;
head[a]:=tot;
end; procedure qsort(l,r:longint);
var i,j,mid:longint;
begin
i:=l; j:=r; mid:=b[(l+r)>>];
repeat
while mid>b[i] do inc(i);
while mid<b[j] do dec(j);
if i<=j then
begin
swap(h[i],h[j]);
swap(b[i],b[j]);
inc(i); dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end; function lca(x,y:longint):longint;
var i,d:longint;
begin
if dep[x]<dep[y] then swap(x,y);
d:=dep[x]-dep[y];
for i:= to do
if d and (<<i)> then x:=f[x,i];
for i:= downto do
if f[x,i]<>f[y,i] then
begin
x:=f[x,i]; y:=f[y,i];
end;
if x=y then exit(x);
exit(f[x,]);
end; procedure dfs(u:longint);
var e,v,i:longint;
begin
for i:= to do
begin
if dep[u]<(<<i) then break;
f[u,i]:=f[f[u,i-],i-];
end;
inc(time); dfn[u]:=time;
flag[u]:=;
e:=head[u];
while e<> do
begin
v:=vet[e];
if flag[v]= then
begin
f[v,]:=u;
dep[v]:=dep[u]+;
dfs(v);
end;
e:=next[e];
end;
end; procedure add1(a,b:longint);
begin
if a=b then exit;
inc(tot);
next1[tot]:=head1[a];
vet1[tot]:=b;
len1[tot]:=abs(dep[a]-dep[b]);
head1[a]:=tot;
end; procedure dfs2(u:longint);
var e,v:longint;
begin
size[u]:=c[u];
g[u]:=;
if c[u]= then begin dp[u,]:=; dp[u,]:=; end
else begin dp[u,]:=-maxlongint div ; dp[u,]:=maxlongint div ; end;
e:=head1[u];
while e<> do
begin
v:=vet1[e];
dfs2(v);
ans:=ans+size[v]*g[u]+size[u]*g[v]+size[u]*size[v]*len1[e];
size[u]:=size[u]+size[v];
g[u]:=g[u]+g[v]+size[v]*len1[e];
ans1:=max(ans1,dp[u,]+dp[v,]+len1[e]);
ans2:=min(ans2,dp[u,]+dp[v,]+len1[e]);
dp[u,]:=max(dp[u,],dp[v,]+len1[e]);
dp[u,]:=min(dp[u,],dp[v,]+len1[e]);
e:=next1[e];
end;
head1[u]:=;
end; procedure solve;
var q,top,i,now,m,p:longint;
begin
tot:=;
read(m);
for i:= to m do
begin
read(h[i]); b[i]:=dfn[h[i]];
c[h[i]]:=;
end;
qsort(,m);
//q:=;
//for i:= to m do
//if lca(h[i],h[q])<>h[q] then begin inc(q); h[q]:=h[i]; end;
stk[]:=; top:=;
for i:= to m do
begin
now:=h[i]; p:=lca(now,stk[top]);
while true do
begin
if dep[p]>=dep[stk[top-]] then
begin
add1(p,stk[top]); dec(top);
if stk[top]<>p then begin inc(top); stk[top]:=p; end;
break;
end;
add1(stk[top-],stk[top]); dec(top);
end;
if stk[top]<>now then begin inc(top); stk[top]:=now; end;
end;
for i:=top- downto do add1(stk[i],stk[i+]);
ans:=; ans1:=-maxlongint div ; ans2:=maxlongint div ;
dfs2();
writeln(ans,' ',ans2,' ',ans1);
for i:= to m do c[h[i]]:=;
end; begin readln(n);
for i:= to n- do
begin
readln(x,y);
add(x,y,);
add(y,x,);
end;
dfs();
readln(que);
for i:= to que do solve; end.
%了XYZ(虚树发明者)论文后的新的建虚树方法,简明易懂:
1:加入所有原关键点并按DFS序排序
2:将排序后两两相邻点对的LCA加入后去重,并再次排序
3:将第二次排序后的点依次入栈,若栈顶元素y非插入元素x的祖先则退栈,直到栈顶元素为x的祖先为止,链接x,y
 var head,vet,next,len,
head1,vet1,next1,len1,
h,stk,b,dep,dfn,flag,c,d:array[..]of longint;
dp:array[..,..]of longint;
size,g:array[..]of int64;
f:array[..,..]of longint;
n,i,tot,que,ans1,ans2,time,x,y:longint;
ans:int64; procedure swap(var x,y:longint);
var t:longint;
begin
t:=x; x:=y; y:=t;
end; function min(x,y:int64):int64;
begin
if x<y then exit(x);
exit(y);
end; function max(x,y:int64):int64;
begin
if x>y then exit(x);
exit(y);
end; procedure add(a,b,c:longint);
begin
inc(tot);
next[tot]:=head[a];
vet[tot]:=b;
len[tot]:=c;
head[a]:=tot;
end; procedure qsort1(l,r:longint);
var i,j,mid:longint;
begin
i:=l; j:=r; mid:=b[(l+r)>>];
repeat
while mid>b[i] do inc(i);
while mid<b[j] do dec(j);
if i<=j then
begin
swap(h[i],h[j]);
swap(b[i],b[j]);
inc(i); dec(j);
end;
until i>j;
if l<j then qsort1(l,j);
if i<r then qsort1(i,r);
end; procedure qsort2(l,r:longint);
var i,j,mid:longint;
begin
i:=l; j:=r; mid:=b[(l+r)>>];
repeat
while mid>b[i] do inc(i);
while mid<b[j] do dec(j);
if i<=j then
begin
swap(d[i],d[j]);
swap(b[i],b[j]);
inc(i); dec(j);
end;
until i>j;
if l<j then qsort2(l,j);
if i<r then qsort2(i,r);
end; function lca(x,y:longint):longint;
var i,d:longint;
begin
if dep[x]<dep[y] then swap(x,y);
d:=dep[x]-dep[y];
for i:= to do
if d and (<<i)> then x:=f[x,i];
for i:= downto do
if f[x,i]<>f[y,i] then
begin
x:=f[x,i]; y:=f[y,i];
end;
if x=y then exit(x);
exit(f[x,]);
end; procedure dfs(u:longint);
var e,v,i:longint;
begin
for i:= to do
begin
if dep[u]<(<<i) then break;
f[u,i]:=f[f[u,i-],i-];
end;
inc(time); dfn[u]:=time;
flag[u]:=;
e:=head[u];
while e<> do
begin
v:=vet[e];
if flag[v]= then
begin
f[v,]:=u;
dep[v]:=dep[u]+;
dfs(v);
end;
e:=next[e];
end;
end; procedure add1(a,b:longint);
begin
if a=b then exit;
inc(tot);
next1[tot]:=head1[a];
vet1[tot]:=b;
len1[tot]:=abs(dep[a]-dep[b]);
head1[a]:=tot;
end; procedure dfs2(u:longint);
var e,v:longint;
begin
size[u]:=c[u];
g[u]:=;
if c[u]= then begin dp[u,]:=; dp[u,]:=; end
else begin dp[u,]:=-maxlongint div ; dp[u,]:=maxlongint div ; end;
e:=head1[u];
while e<> do
begin
v:=vet1[e];
dfs2(v);
ans:=ans+size[v]*g[u]+size[u]*g[v]+size[u]*size[v]*len1[e];
size[u]:=size[u]+size[v];
g[u]:=g[u]+g[v]+size[v]*len1[e];
ans1:=max(ans1,dp[u,]+dp[v,]+len1[e]);
ans2:=min(ans2,dp[u,]+dp[v,]+len1[e]);
dp[u,]:=max(dp[u,],dp[v,]+len1[e]);
dp[u,]:=min(dp[u,],dp[v,]+len1[e]);
e:=next1[e];
end;
head1[u]:=;
end; procedure solve;
var q,top,i,now,m,p:longint;
begin
tot:=;
read(m);
for i:= to m do
begin
read(h[i]); b[i]:=dfn[h[i]];
c[h[i]]:=;
end;
qsort1(,m);
q:=;
for i:= to m do
begin
inc(q); d[q]:=h[i]; flag[h[i]]:=;
end;
for i:= to m- do
begin
p:=lca(h[i],h[i+]);
if flag[p]= then begin flag[p]:=; inc(q); d[q]:=p; end;
end;
for i:= to q do b[i]:=dfn[d[i]];
qsort2(,q); stk[]:=d[]; top:=;
for i:= to q do
begin
x:=d[i];
while true do
begin
y:=stk[top];
if lca(x,y)<>y then dec(top)
else
begin
add1(y,x);
break;
end;
end;
inc(top); stk[top]:=x;
end; ans:=; ans1:=-maxlongint div ; ans2:=maxlongint div ;
dfs2(d[]);
writeln(ans,' ',ans2,' ',ans1);
for i:= to m do c[h[i]]:=;
for i:= to q do flag[d[i]]:=;
end; begin
assign(input,'bzoj3611.in'); reset(input);
assign(output,'bzoj3611.out'); rewrite(output);
readln(n);
for i:= to n- do
begin
readln(x,y);
add(x,y,);
add(y,x,);
end;
dfs();
readln(que);
fillchar(flag,sizeof(flag),);
for i:= to que do solve;
close(input);
close(output);
end.
 

【BZOJ3611】大工程(虚树,DFS序,树形DP)的更多相关文章

  1. [HEOI2014][bzoj3611] 大工程 [虚树+dp]

    题面: 传送门 思路: 又是一道虚树入门级的题目,但是这道题的实际难点在于dp 首先,这道题是可以点分治做的,而且因为6s时限随便浪,所以写点分治也不是不可以 但是,dp因为$O\left(n\rig ...

  2. 【BZOJ】3991: [SDOI2015]寻宝游戏 虚树+DFS序+set

    [题意]给定n个点的带边权树,对于树上存在的若干特殊点,要求任选一个点开始将所有特殊点走遍后返回.现在初始没有特殊点,m次操作每次增加或减少一个特殊点,求每次操作后的总代价.n,m<=10^5. ...

  3. [JSOI2016]最佳团体 DFS序/树形DP

    题目 洛谷 P4322 [JSOI2016]最佳团体 Description 茜茜的舞蹈团队一共有\(N\)名候选人,这些候选人从\(1\)到\(N\)编号.方便起见,茜茜的编号是\(0\)号.每个候 ...

  4. luogu P4103 [HEOI2014]大工程 虚树 + 树形 DP

    Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道.  我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上.  在 2 个国家 a,b 之间建一条新通 ...

  5. 洛谷P4103 [HEOI2014]大工程(虚树 树形dp)

    题意 链接 Sol 虚树. 首先建出虚树,然后直接树形dp就行了. 最大最小值直接维护子树内到该节点的最大值,然后合并两棵子树的时候更新一下答案. 任意两点的路径和可以考虑每条边两边的贡献,\(d[x ...

  6. BZOJ.3611.[HEOI2014]大工程(虚树 树形DP)

    题目链接 要求的和.最大值.最小值好像都可以通过O(n)的树形DP做,总询问点数<=2n. 于是建虚树就可以了.具体DP见DP()函数,维护三个值sum[],mx[],mn[]. sum[]要开 ...

  7. bzoj 3611: [Heoi2014]大工程 虚树

    题目: 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通道需要的代价为树上 ...

  8. 【HEOI2014】大工程<虚树>

    虚树 我们每天都用心思索着,这究竟是为了什么呢?我想我也不知道,只是觉得如果人不思考问题就很无聊. 我觉得虚树不是什么数据结构,就是一种技巧或者工具.它能把树中\(k\)个关键点以\(O(klogk) ...

  9. bzoj 3611(洛谷 4103) [Heoi2014]大工程——虚树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3611 https://www.luogu.org/problemnew/show/P4103 ...

  10. BZOJ 3611 [Heoi2014]大工程 ——虚树

    虚树第二题.... 同BZOJ2286 #include <map> #include <cmath> #include <queue> #include < ...

随机推荐

  1. access处理重复创建表的方法。

    第一种,使用MSysObjects表查找表名为当前创建表的名字的内容,相当于普通查询,但是access数据库有一个安全问题,就是有时候一开始是没有权限去调这些系统表的,这时可以再2007的access ...

  2. NSCopying协议和copy方法

    不是所有的对象都支持 copy需要继承NSCopying 协议(实现 copyWithZone: 方法)同样,需要继承NSMutableCopying 协议才可以使用mutableCopy(实现 mu ...

  3. shell脚本自动部署及监控

    一.shell脚本部署nginx反向代理和三个web服务 1 对反向代理服务器进行配置 #!/bin/bash #修改用户交互页面 用户输入参数执行相应的参数 #安装epel扩展包和nginx fun ...

  4. Java——舞动的排序

    一.冒泡排序: http://v.youku.com/v_show/id_XMzMyOTAyMzQ0.html //冒泡排序 public class Bubbling { public static ...

  5. HTML5<picture>元素

    HTML5<picture>元素可以设置多张图片 <!DOCTYPE html><html><head><meta http-equiv=&quo ...

  6. AOP日志组件 多次获取post参数

    AOP日志组件 多次获取post参数 需求:新增接口日志组件.通过拦截器对接口URL进行拦截处理,然后将接口post请求的参数与结果,写入日志表. 问题:POST方法的参数是存储在request.ge ...

  7. vuejs 中 select 动态填充数据,后台的数据

           selected:"A" 对       selected:A 错.  变量不用引号. 内容一定要引号. https://jsfiddle.net/rgnuaw30/ ...

  8. POJ-3050-Hoscotch

    这是一道简单的深搜题目,题意说的是给一个5*5的棋盘,里面填满数字,然后跳到一个格子上,这是第一步,接着向上下左右四个方向任意一个方向走一步,一共走6步,问我们走过的数字组成的一个6位数有多少种不同的 ...

  9. break、continue、exit、return的区别和对比

    break.continue.exit.return的区别和对比 一:说明 break.continue在条件循环语句及循环语句(for.while.if等)中用于控制程序的走向:而exit则用于种植 ...

  10. Linux中的定时任务简单操作实例

    今天,我怀着一颗感恩的心,写了一个小小的定时任务,细想还是写个简单的例子吧,希望能帮到你! 首先我在/usr/local/文件夹下创建了一个文件,hah.sh文件 在hah.sh里面编写shell脚本 ...