Loading

CF685B Kay and Snowflake

思路

  1. 从下往上处理每个子树的重心。
  2. 对于任意点 \(u\),其所在子树的中心一定在 \(u\)\(ans[to]\) 之间,\(ans[to]\) 是重儿子 \(to\) 的重心结点。
  3. 对于任意一点 \(u\),其所在子树的重心深度一定不大于 \(ans[to]\)

image

代码

假设一个结点 \(u\) 的子树大小为 \(sz[u]\)

对于 \(u\),我们从它的重儿子结点的答案结点开始向上跳,直到跳到的点 \(p\) 的子树大小 \(sz[p]\) 的两倍大于 \(u\) 的子树大小,这时 \(sz[u] - sz[p] < \dfrac{sz[u]}{2}\), \(u\) 的每一个子树大小也不可能超过 \(\dfrac{sz[u]}{2}\)

所以 \(p\) 就是 \(u\) 的重心结点。

#include <bits/stdc++.h>

using namespace std;

const int N = 300010;

struct edge {
    int to, next;
} e[N];

int head[N], idx = 1;

void add(int u, int v) {
    idx++, e[idx].to = v, e[idx].next = head[u], head[u] = idx;
}

int n, q, sz[N], son[N], ans[N], fa[N];

void dfs(int u) {
    sz[u] = 1;                  // 子树大小
    for (int i = head[u]; i; i = e[i].next) {
        int to = e[i].to;
        fa[to] = u;             // 父亲结点
        dfs(to);
        sz[u] += sz[to];
        if (sz[son[u]] < sz[to]) son[u] = to;// 重儿子
    }

    if (!head[u]) {             // 叶子结点
        ans[u] = u;
        return;
    }

    int p = ans[son[u]];
    while (sz[p] * 2 <= sz[u]) p = fa[p];
    ans[u] = p;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n >> q;
    for (int i = 2; i <= n; i++) {
        int fa;
        cin >> fa;
        add(fa, i);
    }

    dfs(1);

    while (q--) {
        int x;
        cin >> x;
        cout << ans[x] << '\n';
    }
    return 0;
}
posted @ 2024-08-08 10:29  SunnyYuan  阅读(4)  评论(0编辑  收藏  举报