题解 P6584 【重拳出击】
SymphonyOfEuler · · 题解
题目意思比较清楚,不解释。
思路:
这题可以用DFS序线段树做。DFS序线段树就是在线段树操作之前DFS把这个树跑一遍,相当于DFS遍历一遍,把每个点以遍历的顺序标号。根据题目条件,小Z 初始时在
如图:
我们给每个有 Youyou 点一个权值,表示离根多远,方便查询。我们用线段树维护区间最大值,就知道往哪里走了。
考虑达到新点之后的操作,不能再以新的节点为根遍历一遍,否则复杂度会很高。要使用换根的方法优化复杂度。
设新点为
做一个思路的总结:
先以
然后用线段树查
注意事项:
-
前项星pool数组开2倍
-
线段树开4倍
代码:
/* by JS */
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 4 * 1e5 + 5;
#define lc p << 1
#define rc p << 1 | 1
int n, m, k, x, Count, nn, cnt, head[MAXN], pre[MAXN], dep[MAXN], fa[MAXN], siz[MAXN], id[MAXN], kc[MAXN], Max[
4 * MAXN], Tag[4 * MAXN], maxnum, pos;
bool hasyy[MAXN], flag;
struct Node {
int v, nxt;
} pool[2 * MAXN];
inline int init(int u, int father) {
cnt++;
pre[u] = cnt, dep[u] = dep[father] + 1, fa[u] = father, siz[u] = 1, id[cnt] = u;
if (hasyy[u]) kc[u] = dep[u];
for (int i = head[u]; i > 0; i = pool[i].nxt) {
if (pool[i].v == father) continue;
siz[u] += init(pool[i].v, u);
}
return siz[u];
}
void add(int u, int v) {
nn++;
pool[nn].v = v;
pool[nn].nxt = head[u];
head[u] = nn;
}
struct Segment_Tree {
static void push_up(int p) {
Max[p] = max(Max[lc], Max[rc]);
}
inline void build_tree(int p, int l, int r) {
if (l == r) {
Max[p] = kc[id[l]];
return;
}
int mid = (l + r) / 2;
build_tree(lc, l, mid);
build_tree(rc, mid + 1, r);
push_up(p);
}
static void move_tag(int p, int tag) {
int maxn = Max[p];
Max[p] = max(0, maxn + tag);
Tag[p] += tag;
}
static void push_down(int p) {
if (Tag[p]) {
move_tag(lc, Tag[p]);
move_tag(rc, Tag[p]);
Tag[p] = 0;
}
}
inline int query_max(int p, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return Max[p];
push_down(p);
int res = 0;
int mid = (l + r) / 2;
if (ql <= mid) {
res = max(res, query_max(lc, l, mid, ql, qr));
}
if (mid < qr) {
res = max(res, query_max(rc, mid + 1, r, ql, qr));
}
return res;
}
inline int dfs_query(int cur) {
if (cur != fa[x]) {
int ql = pre[cur];
int qr = pre[cur] + siz[cur] - 1;
return query_max(1, 1, n, ql, qr);
}
int res = 0;
if (pre[x] - 1 > 0) {
int qr = pre[x] - 1;
res = query_max(1, 1, n, 1, qr);
}
if (pre[x] + siz[x] <= n) {
int ql = pre[x] + siz[x];
res = max(res, query_max(1, 1, n, ql, n));
}
return res;
}
inline void update(int p, int l, int r, int ql, int qr, int q) {
if (ql <= l && r <= qr) {
Max[p] = max(Max[p] + q, 0);
Tag[p] += q;
return;
}
push_down(p);
int mid = (l + r) / 2;
if (ql <= mid) {
update(lc, l, mid, ql, qr, q);
}
if (mid < qr) {
update(rc, mid + 1, r, ql, qr, q);
}
push_up(p);
}
inline void dfs_update(int cur, int q) {
if (cur != fa[x]) {
int ql = pre[cur];
int qr = pre[cur] + siz[cur] - 1;
update(1, 1, n, ql, qr, q);
} else {
if (pre[x] - 1 > 0) {
int qr = pre[x] - 1;
update(1, 1, n, 1, qr, q);
}
if (pre[x] + siz[x] <= n) {
int ql = pre[x] + siz[x];
update(1, 1, n, ql, n, q);
}
}
}
} segtree;
inline void solve() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 0, u, v; i < n - 1; ++i) {
cin >> u >> v;
add(u, v);
add(v, u);
}
cin >> m;
while (m--) {
int a;
cin >> a;
hasyy[a] = true;
}
cin >> k >> x;
dep[0] = -1;
init(x, 0);
segtree.build_tree(1, 1, n);
while (1) {
pos = maxnum = flag = 0;
++Count;
for (int i = head[x]; i > 0; i = pool[i].nxt) {
if (!segtree.dfs_query(pool[i].v)) continue;
if (maxnum < segtree.dfs_query(pool[i].v)) {
maxnum = max(maxnum, segtree.dfs_query(pool[i].v));
pos = pool[i].v;
flag = false;
} else if (maxnum == segtree.dfs_query(pool[i].v)) flag = true;
}
if (maxnum <= k) break;
if (flag) {
segtree.update(1, 1, n, 1, n, -1);
continue;
}
segtree.dfs_update(pos, -2), x = pos;
}
cout << Count << '\n';
}
int main() {
solve();
return 0;
}