Blog of RuSun

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

P2495 [SDOI2011] 消耗战

P2495 [SDOI2011] 消耗战

注意到一条不包含关键点的链等价于一条边,边权为链上边权的最小值,建出虚树后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
#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 = 25e4 + 10, M = 20, inf = 1e5;
bool key[N];
int top, stk[N];
LL f[N];
int n, m, q, d[N], h[N];
int stmp, dfn[N], lg[N], p[N][M], w[N][M];
struct Edge { int v, w; };
vector <Edge> e[N], g[N];
void dfs (int u = 1, int fa = 0)
{
dfn[u] = ++stmp;
d[u] = d[fa] + 1;
p[u][0] = fa;
for (int i = 1; 1 << i < d[u]; ++i)
{
p[u][i] = p[p[u][i - 1]][i - 1];
w[u][i] = min(w[u][i - 1], w[p[u][i - 1]][i - 1]);
}
for (Edge i : e[u]) if (i.v ^ fa)
{
w[i.v][0] = i.w;
dfs(i.v, u);
}
}
int lca (int a, int b)
{
if (d[a] < d[b]) swap(a, b);
for (int i = lg[d[a] - d[b]]; ~i; i = lg[d[a] - d[b]])
a = p[a][i];
if (a == b) return a;
for (int i = lg[d[a] - 1]; ~i; --i)
if (p[a][i] ^ p[b][i])
a = p[a][i], b = p[b][i];
return p[a][0];
}
int calc (int a, int b)
{
int res = inf;
if (d[a] < d[b]) swap(a, b);
for (int i = lg[d[a] - d[b]]; ~i; i = lg[d[a] - d[b]])
res = min(res, w[a][i]), a = p[a][i];
if (a == b) return res;
for (int i = lg[d[a] - 1]; ~i; --i)
if (p[a][i] ^ p[b][i])
{
res = min(res, min(w[a][i], w[b][i]));
a = p[a][i], b = p[b][i];
}
return p[a][0];
}
LL dp (int u = 1)
{
f[u] = 0;
for (Edge i : g[u])
f[u] += key[i.v] ? i.w : min(dp(i.v), (LL)i.w);
return f[u];
}
int main ()
{
read(n);
for (int i = 1, a, b, c; i < n; ++i)
{
read(a, b, c);
e[a].pb((Edge){b, c}), e[b].pb((Edge){a, c});
}
lg[0] = -1;
for (int i = 2; i <= n; ++i)
lg[i] = lg[i >> 1] + 1;
dfs();
read(q);
auto add = [&](int u, int v) { g[u].pb((Edge){v, calc(u, v)}); };
while (q--)
{
read(m);
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]; });
g[stk[top = 1] = 1].clear();
for (int i = 1; i <= m; ++i) if (h[i] ^ 1)
{
int t = 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;
}
else add(stk[top - 1], stk[top]), --top;
}
g[stk[++top] = h[i]].clear();
}
for (; top > 1; --top)
add(stk[top - 1], stk[top]);
write(dp()), puts("");
for (int i = 1; i <= m; ++i)
key[h[i]] = false;
}
return 0;
}