【CodeForces 686 D. 】 【树的重心性质】

D. Kay and Snowflake
time limit per test 3 seconds
memory limit per test 256 megabytes
input standard input
output standard output
After the piece of a devilish mirror hit the Kay’s eye, he is no longer interested in the beauty of the roses. Now he likes to watch snowflakes.

Once upon a time, he found a huge snowflake that has a form of the tree (connected acyclic graph) consisting of n nodes. The root of tree has index 1. Kay is very interested in the structure of this tree.
After doing some research he formed q queries he is interested in. The i-th query asks to find a centroid of the subtree of the node vi. Your goal is to answer all queries.
Subtree of a node is a part of tree consisting of this node and all it’s descendants (direct or not). In other words, subtree of node v is formed by nodes u, such that node v is present on the path from u to root.
Centroid of a tree (or a subtree) is a node, such that if we erase it from the tree, the maximum size of the connected component will be at least two times smaller than the size of the initial tree (or a subtree).
Input
The first line of the input contains two integers n and q (2 ≤ n ≤ 300 000, 1 ≤ q ≤ 300 000) — the size of the initial tree and the number of queries respectively.
The second line contains n - 1 integer p2, p3, …, pn (1 ≤ pi ≤ n) — the indices of the parents of the nodes from 2 to n. Node 1 is a root of the tree. It’s guaranteed that pi define a correct tree.
Each of the following q lines contain a single integer vi (1 ≤ vi ≤ n) — the index of the node, that define the subtree, for which we want to find a centroid.
Output
For each query print the index of a centroid of the corresponding subtree. If there are many suitable nodes, print any of them. It’s guaranteed, that each subtree has at least one centroid.
Example
input
7 4
1 1 3 3 5 3
1
2
3
5
output
3
2
3
6
Note
这里写图片描述
The first query asks for a centroid of the whole tree — this is node 3. If we delete node 3 the tree will split in four components, two of size1 and two of size 2.
The subtree of the second node consists of this node only, so the answer is 2.
Node 3 is centroid of its own subtree.
The centroids of the subtree of the node 5 are nodes 5 and 6 — both answers are considered correct.

题意 给一颗有向边的树,根节点为 1,q次询问,询问以该点为根节点的子树的重心编号。

补充知识点 :
树的重心
定义 以这个点为根,那么所有的子树(不算整个树自身)的大小都不超过整个树大小的一半。

性质 1 :树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有多个重心,他们的距离和一样。
性质 2 :把两棵树通过某一点相连得到一颗新的树,新的树的重心必然在连接原来两棵树重心的路径上。
性质 3 :一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。

代码

#include
using namespace std;
typedef pair<int,int>pii;
#define first fi
#define second se
#define  LL long long
#define fread() freopen("in.txt","r",stdin)
#define fwrite() freopen("out.txt","w",stdout)
#define CLOSE() ios_base::sync_with_stdio(false)

const int MAXN = 3e5+10;
const int MAXM = 1e6;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;

struct Edge{
    int from,to,nexts;
}edge[MAXN];
int head[MAXN],top;
void init(){
    memset(head,-1,sizeof(head));
    top=0;
} 
void addedge(int a,int b){
    Edge e={a,b,head[a]};
    edge[top]=e;head[a]=top++;
}
int n,m;
int fa[MAXN];  //父亲节点
int ans[MAXN];  //答案
int num[MAXN];  // num[i]以i为根节点的子树的总节点数

void dfs(int now){
    ans[now]=now; // 回溯前 赋初值
    num[now]=1;
    for(int i=head[now];i!=-1;i=edge[i].nexts){
        int v=edge[i].to;
        dfs(v);
        num[now]+=num[v]; 
    } 
    for(int i=head[now];i!=-1;i=edge[i].nexts){
        int v=edge[i].to;//遍历,找到以now为根节点的树,重心在哪个子树上
        if(num[v]*2>num[now])//根据定义
            ans[now]=ans[v];
    }
    while((num[now]-num[ans[now]])*2>num[now]) 
        ans[now]=fa[ans[now]];// 性质2,两个子树合并之后,重心在两个重心的路径上。更新ans[now]
}
int main(){
    CLOSE();
//  fread();
//  fwrite();
    int q;
    init();
    scanf("%d%d",&n,&q);m=n-1;
    for(int i=2;i<=n;i++) {
        scanf("%d",&fa[i]);
        addedge(fa[i],i);
    }
    dfs(1);
//  for(int i=1;i<=n;i++) printf("%d ",num[i]);
    while(q--){
        int a;scanf("%d",&a);
        printf("%d\n",ans[a]);
    }
    return 0;
}

你可能感兴趣的:(思维,CF,刷题之旅,树形DP,树的直径,重心,分治)