[CF 685B] Kay and Snowflake

原题传送门

题目大意:

给定一棵树,n个节点,给定q个询问,给出n-1个数表示2-n的节点的父节点,每个询问节点给出一个值x,询问以x为根的子树的重心节点

思路浅析:

初始思路是直接跑dfs求出最大子树的最小权值对应的根节点,将其作为一个子树的重心,但是跑着题肯定是会毫无疑问的T飞的,我们需要利用一个树的重心的性质:重心的最大子树不超过整棵树的一半,否则这个点肯定不是重心

code:

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 300010;

struct edge
{
    int to, nxt;
} e[N << 1];

int cnt;
int x, y;
int n, q;
int head[N], son[N], ans[N], fa[N];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (!isdigit(ch))
        f = (ch == '-') ? -1 : 1, ch = getchar();
    while (isdigit(ch))
        x = x * 10 + (ch - '0'), ch = getchar();
    return x * f;
}

inline void add(int x, int y) { e[++cnt].to = y, e[cnt].nxt = head[x], head[x] = cnt; }

inline void dfs(int x, int f) //离线预处理
{
    int res = 0; //保证第一次能够合法查询且有一个极小值,那么直接把他设为0
    son[x] = 1;
    ans[x] = x;                            //先默认该点是其子树的根节点
    for (int i = head[x]; i; i = e[i].nxt) //前向星遍历树
    {
        if (e[i].to == f)
            continue;
        dfs(e[i].to, x);
        son[x] += son[e[i].to];
        if (son[e[i].to] > son[res])
            res = e[i].to;
    }
    if ((son[res] << 1) > son[x]) /* 利用树的重心性质解题 */
    /* 以某个点为根,其所有的子树的大小都不差过整个树的一半 */
    {
        int temp = ans[res];
        while (((son[x] - son[temp]) << 1) > son[x])
            temp = fa[temp];
        ans[x] = temp;
    }
}

main()
{
    n = read(), q = read();
    for (int i = 2; i <= n; ++i)
        x = read(), add(i, x), add(x, i), fa[i] = x;

    dfs(1, 0);
    for (int i = 1; i <= q; ++i)
    {
        x = read();
        std::cout << ans[x], puts("");
    }
}
上一篇:Twitter-Snowflake:自增ID算法


下一篇:# Twitter雪花算法(Snowflake)