BZOJ 3611

传送门

先搞出来虚树,然后树形DP一下就没了…

本来打算还像消耗战那样把DP扔到建树过程里,后来发现似乎不行…

Tips

$f(t)$为$t$子树中关键点个数
$g(t)$为$t$子树中所有关键点到$t$距离之和


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
program bzoj_3611;
const inf=maxlongint>>1;
var n,i,j,a,b,q,tot,logn,len,top,minans,maxans:longint;
dep,lst,dfn,seq,s,min,max:array[0..1000000]of longint;
l:array[1..2000000]of record ed,pre:longint; end;
f,g:array[1..1000000]of int64;
fa:array[0..1000000,0..20]of longint;
key:array[1..1000000]of boolean;
sum:int64;

procedure link(a,b:longint);
begin
inc(tot);
l[tot].pre:=lst[a];
lst[a]:=tot;
l[tot].ed:=b;
end;

procedure swap(var a,b:longint);
var p:longint;
begin
p:=a;
a:=b;
b:=p;
end;

procedure dfs(t:longint);
var k:longint;
begin
inc(tot);
dfn[t]:=tot;
k:=lst[t];
while k<>0 do
begin
if l[k].ed<>fa[t,0] then
begin
fa[l[k].ed,0]:=t;
dep[l[k].ed]:=dep[t]+1;
dfs(l[k].ed);
end;
k:=l[k].pre;
end;
end;

procedure qsort(l,r:longint);
var i,j,mid:longint;
begin
i:=l;
j:=r;
mid:=dfn[seq[(l+r)>>1]];
repeat
while dfn[seq[i]]<mid do inc(i);
while dfn[seq[j]]>mid do dec(j);
if i<=j then
begin
swap(seq[i],seq[j]);
inc(i);
dec(j);
end;
until i>j;
if i<r then qsort(i,r);
if l<j then qsort(l,j);
end;

function lca(a,b:longint):longint;
var l:longint;
begin
if dep[a]<dep[b] then swap(a,b);
for l:=logn downto 0 do if dep[fa[a,l]]>=dep[b] then a:=fa[a,l];
if a=b then exit(a);
for l:=logn downto 0 do if fa[a,l]<>fa[b,l] then
begin
a:=fa[a,l];
b:=fa[b,l];
end;
exit(fa[a,0]);
end;

procedure build;
var i,l:longint;
begin
qsort(1,len);
top:=1;
tot:=0;
s[1]:=1;
key[1]:=(seq[1]=1);
for i:=1 to len do
begin
l:=lca(seq[i],s[top]);
while (top>1)and(dep[l]<=dep[s[top-1]]) do
begin
link(s[top-1],s[top]);
dec(top);
end;
if l<>s[top] then
begin
link(l,s[top]);
s[top]:=l;
key[l]:=false;
end;
if s[top]<>seq[i] then
begin
inc(top);
s[top]:=seq[i];
key[seq[i]]:=true;
end;
end;
while top>1 do
begin
link(s[top-1],s[top]);
dec(top);
end;
end;

procedure dp(t:longint);
var k,d:longint;
begin
if key[t] then min[t]:=0 else min[t]:=inf;
if key[t] then max[t]:=0 else max[t]:=-inf;
f[t]:=ord(key[t]);
g[t]:=0;
k:=lst[t];
while k<>0 do
begin
if l[k].ed<>fa[t,0] then
begin
dp(l[k].ed);
d:=dep[l[k].ed]-dep[t];
if min[t]+min[l[k].ed]+d<minans then minans:=min[t]+min[l[k].ed]+d;
if max[t]+max[l[k].ed]+d>maxans then maxans:=max[t]+max[l[k].ed]+d;
inc(sum,int64(g[t]+f[t]*d)*int64(f[l[k].ed])+int64(g[l[k].ed])*int64(f[t]));
inc(f[t],f[l[k].ed]);
inc(g[t],g[l[k].ed]+f[l[k].ed]*int64(d));
if min[l[k].ed]+d<min[t] then min[t]:=min[l[k].ed]+d;
if max[l[k].ed]+d>max[t] then max[t]:=max[l[k].ed]+d;
end;
k:=l[k].pre;
end;
lst[t]:=0;
end;

begin
readln(n);
logn:=0;
while 1<<logn<=n do inc(logn);
tot:=0;
for i:=1 to n-1 do
begin
readln(a,b);
link(a,b);
link(b,a);
end;
dep[0]:=-1;
dep[1]:=0;
fa[1,0]:=0;
tot:=0;
dfs(1);
for logn:=1 to logn do
for i:=1 to n do fa[i,logn]:=fa[fa[i,logn-1],logn-1];
for i:=1 to n do lst[i]:=0;
readln(q);
for j:=1 to q do
begin
readln(len);
for i:=1 to len do read(seq[i]);
build;
minans:=inf;
maxans:=-inf;
sum:=0;
dp(1);
writeln(sum,' ',minans,' ',maxans);
end;
end.