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

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. iOS开发资源:推送通知相关开源项目--PushSharp、APNS-PHP以及Pyapns等

    PushSharp  (github) PushSharp是一个实现了由服务器端向移动客户端推送消息的开源C#库,支持 iOS (iPhone/iPad APNS). Android (C2DM/GC ...

  2. python 1:列表和字典

    初学Python, 对列表和字典的嵌套使用. phoneBook = [] #列表 list peopleInfo = {} #字典 dict i=0 while i<3: peopleInfo ...

  3. sort函数的使用

    此篇当作自己的笔记(水平太菜,这都一直没搞明白) sort()函数的用法1)sort函数包含在头文件<algroithm>中,还要结合using namespace std2)sort有三 ...

  4. Hermite 矩阵的特征值不等式

    将要学习 关于 Hermite 矩阵的特征值不等式. Weyl 定理 以及推论.   Weyl 定理 Hermann Weyl 的如下定理是大量不等式的基础,这些不等式要么涉及两个 Hermite 矩 ...

  5. a标签目标链接问题

    1.先确定开始文件和目标文件,例如从css.html开始到body.html 2.确定文件寻找路径,因为css.html的父目录是css,而body.html在body目录下,所以需要先退到上一目录h ...

  6. false - (失败的)什么都不做

    总览 (SYNOPSIS) false [忽略命令行参数] false OPTION 描述 (DESCRIPTION) 程序 结束 时, 产生 表示 失败 的 状态码. 下列的 选项 没有 简写 形式 ...

  7. linux虚拟机安装值得注意的几点

    1.建立新的虚拟机时选择自定义安装并选择稍后安装操作系统 2.关键安装命令 tar -xzvf  VMwareTools-10.0.6-3595377.tar.gz sudo ./wmware-ins ...

  8. Protocol(协议)、Delegate(委托)、DataSource(数据源)

    这里以 UITableViewController 和 UITableView 的关系为例: //--------------------------------------------------- ...

  9. 661. Image Smoother@python

    Given a 2D integer matrix M representing the gray scale of an image, you need to design a smoother t ...

  10. Python 基本数据类型 (二) - 字符串

    str.expandtabs([tabsize]): str类型的expandtabs函数,有一个可选参数tabsize(制表符大小) 详细来说,expandtabs的意思就是,将字符串中的制表符\t ...