求树的每个子树的重心

时间:2022-05-14 20:09:31

前言:

每个子树的重心(p)的定义:删去该点p后,以x为根的子树的所有联通块的大小均不超过 siz[x] / 2

根据这个重心的定义可以知道一棵子树的重心必定在他自己所在的重链中. 所以每次找到他的重儿子为根的子树的重心, 不符合的话就沿着重链往上走直至找到复合要求的重心.

模版题:http://codeforces.com/problemset/problem/685/B

 

#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <queue>
#include <math.h>
#include <cstdio>
#include <iomanip>
#include <time.h>
#include <bitset>
#include <cmath>

#define LL long long
#define INF 0x3f3f3f3f
#define ls nod<<1
#define rs (nod<<1) 1

const double eps = 1e-10;
const int maxn = 3e5   10;
const LL mod = 1e9   7;

int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}
using namespace std;

struct edge {
    int v,nxt;
}e[maxn];

int head[maxn],mx[maxn],ans[maxn];
int siz[maxn],fa[maxn];
int cnt;

void add_edge(int u,int v) {
    e[  cnt].v = v;
    e[cnt].nxt = head[u];
    head[u] = cnt;
}

void dfs(int x) {
    siz[x] = 1;
    ans[x] = x;
    int w = 0;
    for (int i = head[x];~i;i = e[i].nxt) {
        int v = e[i].v;
        dfs(v);
        siz[x]  = siz[v];
        if (siz[v] > w) {
            w = siz[v];
            mx[x] = v;
        }
    }
    int p = ans[mx[x]];
    while (p && p != fa[x]) {
        if (siz[mx[p]]*2 <= siz[x] && (siz[x]-siz[p])*2 <= siz[x]) {
            ans[x] = p;
            break;
        }
        p = fa[p];
    }
}

int main() {
    cnt = 0;
    memset(head,-1, sizeof(head));
    int n,q;
    scanf("%d%d",&n,&q);
    for (int i = 2;i <= n;i  ) {
        int v;
        scanf("%d",&v);
        fa[i] = v;
        add_edge(v,i);
    }
    dfs(1);
    while (q--) {
        int x;
        scanf("%d",&x);
        printf("%dn",ans[x]);
    }
    return 0;
}