Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P4103 [HEOI2014]大工程

P4103 [HEOI2014]大工程

建出虚树,$MAX$ 和 $MIN$ 可以一次树形DP做完,计算 $SUM$ 考虑换根DP。

查看代码
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
#include <cstdio>
#include <vector>
#include <algorithm>
#define pb push_back
using namespace std;
template <class Type>
void read (Type &x)
{
char c;
bool flag = false;
while ((c = getchar()) < '0' || c > '9')
flag |= c == '-';
x = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
x = (x << 3) + (x << 1) + c - '0';
if (flag) x = ~x + 1;
}
template <class Type, class ...Rest>
void read (Type &x, Rest &...y) { read(x); read(y...); }
template <class Type>
void write (Type x)
{
if (x < 0) putchar('-'), x = ~x + 1;
if (x > 9) write(x / 10);
putchar('0' + x % 10);
}
typedef long long LL;
const int N = 1e6 + 10, inf = 1e6;
bool key[N];
int top, stk[N];
LL Sum, r[N], s[N];
int n, q, d[N], dfn[N], h[N], Max, Min;
vector <int> e[N];
struct Edge { int v, w; };
vector <Edge> g[N];
namespace LCA
{
int p[N], sz[N];
int stmp, top[N], son[N];
void dfs1 (int u = 1)
{
sz[u] = 1;
for (int v : e[u]) if (!sz[v])
{
d[v] = d[p[v] = u] + 1;
dfs1(v);
sz[u] += sz[v];
if (sz[v] > sz[son[u]]) son[u] = v;
}
}
void dfs2 (int u = 1, int t = 1)
{
dfn[u] = ++stmp;
top[u] = t;
if (!son[u]) return;
dfs2(son[u], t);
for (int v : e[u]) if (v ^ son[u] && v ^ p[u])
dfs2(v, v);
}
int lca (int a, int b)
{
while (top[a] ^ top[b])
{
if (d[top[a]] < d[top[b]]) swap(a, b);
a = p[top[a]];
}
if (d[a] > d[b]) swap(a, b);
return a;
}
void init () { dfs1(), dfs2(); }
}
void dfs1 (int &_mx, int &_mn, int u = 1)
{
r[u] = key[u], s[u] = 0;
int mx[2] = {-inf, -inf}, mn[2] = {inf, inf};
for (Edge i : g[u])
{
int a = 0, b = inf;
dfs1(a, b, i.v);
r[u] += r[i.v];
s[u] += s[i.v] + (LL)i.w * r[i.v];
a += i.w, b += i.w;
if (a > mx[0]) mx[1] = mx[0], mx[0] = a;
else if (a > mx[1]) mx[1] = a;
if (b < mn[0]) mn[1] = mn[0], mn[0] = b;
else if (b < mn[1]) mn[1] = b;
}
if (key[u])
{
if (0 > mx[0]) mx[1] = mx[0], mx[0] = 0;
else if (0 > mx[1]) mx[1] = 0;
if (0 < mn[0]) mn[1] = mn[0], mn[0] = 0;
else if (0 < mn[1]) mn[1] = 0;
}
Max = max(Max, mx[0] + mx[1]);
Min = min(Min, mn[0] + mn[1]);
_mx = mx[0], _mn = mn[0];
}
void dfs2 (int u = 1)
{
if (key[u]) Sum += s[u];
for (Edge i : g[u])
{
s[i.v] = s[u] + (r[1] - 2ll * r[i.v]) * i.w;
dfs2(i.v);
}
}
int main ()
{
read(n);
for (int i = 1, a, b; i < n; ++i)
{
read(a, b);
e[a].pb(b), e[b].pb(a);
}
LCA::init();
read(q);
auto add = [&](int a, int b) { g[a].pb((Edge){b, d[b] - d[a]}); };
for (int m; q; --q)
{
read(m);
g[stk[top = 1] = 1].clear(); key[1] = false;
for (int i = 1; i <= m; ++i)
read(h[i]), key[h[i]] = true;
sort(h + 1, h + m + 1, [&](int a, int b) { return dfn[a] < dfn[b]; });
for (int i = 1; i <= m; ++i) if (h[i] ^ 1)
{
int t = LCA::lca(h[i], stk[top]);
if (t ^ stk[top])
{
for (; dfn[t] < dfn[stk[top - 1]]; --top)
add(stk[top - 1], stk[top]);
if (dfn[t] > dfn[stk[top - 1]])
{
g[t].clear();
add(t, stk[top]);
stk[top] = t;
key[t] = false;
}
else add(stk[top - 1], stk[top]), --top;
}
g[stk[++top] = h[i]].clear();
}
for (; top > 1; --top)
add(stk[top - 1], stk[top]);
int _mx, _mn;
Sum = 0, Max = 0, Min = inf;
dfs1(_mx, _mn), dfs2();
write(Sum >> 1), putchar(' '), write(Min), putchar(' '), write(Max), puts("");
}
return 0;
}