给你一个树N个点,再给出Q个询问,问以x为根的子树中,重心是哪个?
2≤n≤300000,1≤q≤30000
Sol:
从下到上,根据性质做一下.
1:如果某个点x,其子树y的大小超过总结点个数一半,则重心在y这个子树中。
2:如果某个树的重心点,其上方点的个数多于其下方点的,则重心要上移
#include <bits/stdc++.h> using namespace std; const int N = 300000+10; int n,q; vector<int> G[N]; ///存图 int ans[N]; ///答案 int son[N]; ///包括自身在内有多少子树结点 int fa[N]; ///输入用,同时代表这个点的父亲 void dfs(int u){ ans[u] = u;//当只有一个点时,重心为其自己 son[u] = 1; for(int i = 0;i < G[u].size();i++){ int v = G[u][i]; dfs(v); son[u] += son[v]; } for(int i = 0;i < G[u].size();i++) if(son[G[u][i]]*2 > son[u]) //如果有一个子树超过总个数一半,则重心在这个子树中 ans[u] = ans[G[u][i]]; while((son[u]-son[ans[u]])*2 > son[u]) //如果当前重心上方的点,比它下方的点要多,则重心要进行移动 ans[u] = fa[ans[u]]; } int main(void) { scanf("%d%d",&n,&q); for(int i = 2;i <= n;i++){ scanf("%d",&fa[i]); G[fa[i]].push_back(i); } dfs(1); for(int i = 1;i <= q;i++){ int qq; scanf("%d",&qq); printf("%d\n",ans[qq]); } return 0; }