Blog of RuSun

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

CF613D Kingdom and its Cities

LuoGu: CF613D Kingdom and its Cities

CF: D. Kingdom and its Cities

先将 $-1$ 判掉,这样任意两个关键点之间都有点可以删。建虚树后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
#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);
}
const int N = 1e5 + 10;
bool key[N];
int top, stk[N];
int n, m, q, d[N], p[N], dfn[N], h[N];
vector <int> e[N], g[N];
namespace LCA
{
int stmp, top[N], sz[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 dp (int u, int &s, bool &t)
{
s = 0, t = key[u];
int cnt = 0;
for (int v : g[u])
{
int a; bool b;
dp(v, a, b);
s += a; cnt += b;
}
if (key[u]) s += cnt;
else cnt > 1 ? ++s : t = cnt == 1;
}
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);
while (q--)
{
read(m);
key[1] = false;
for (int i = 1; i <= m; ++i)
read(h[i]), key[p[h[i]]] = false;
for (int i = 1; i <= m; ++i) key[h[i]] = true;
bool flag = false;
for (int i = 1; i <= m && !flag; ++i)
flag |= key[p[h[i]]];
if (flag) { puts("-1"); continue; }
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::lca(stk[top], h[i]);
if (t ^ stk[top])
{
for (; dfn[t] < dfn[stk[top - 1]]; --top)
g[stk[top - 1]].pb(stk[top]);
if (dfn[t] > dfn[stk[top - 1]])
{
g[t].clear();
g[t].pb(stk[top]);
stk[top] = t;
key[t] = false;
}
else g[stk[top - 1]].pb(stk[top]), --top;
}
g[stk[++top] = h[i]].clear();
}
for (; top > 1; --top)
g[stk[top - 1]].pb(stk[top]);
int a; bool b; dp(1, a, b);
write(a), puts("");
}
return 0;
}