cf685 B. Kay and Snowflake(树形dp,树的重心)
题意:
找每棵子树的重心。(叙述与原题意有点不同,但可以按这个做)
思路:
首先dfs,求每棵子树的大小 sz[u] ,以及最大的直接儿子子树的大小 mx[u]
以 u-子树 中的某点 cen 为重心,最大的连通块大小为 get = max(sz[u]-sz[cen], mx[cen])
当重心沿着树链往上走(不超过u)时,get要么单调递增,要么先递减后递增。那么每个让 v-子树的重心往上走,尝试更新答案。
注意每个重心往上走的过程是单调的,不需要往回走。这保证了复杂度是 \(O(n)\)
const int N = 3e5 + 5;
int n, q, fa[N];
int h[N], e[N], ne[N], idx;
void add(int a, int b) {
e[++idx] = b, ne[idx] = h[a], h[a] = idx;
}
int sz[N], mx[N]; //最大的直接儿子子树的大小
void dfs1(int u)
{
sz[u] = 1;
for(int i = h[u]; i; i = ne[i])
{
int v = e[i]; dfs1(v);
sz[u] += sz[v];
mx[u] = max(mx[u], sz[v]);
}
}
int get(int u, int cen)
{
return max(sz[u]-sz[cen], mx[cen]);
}
int ans[N];
void dfs2(int u)
{
ans[u] = u;
for(int i = h[u]; i; i = ne[i])
{
int v = e[i]; dfs2(v);
for(int p = ans[v]; p != u; p = fa[p])
{
if(get(u, ans[u]) > get(u, p)) ans[u] = p;
if(get(u, fa[p]) >= get(u, p)) break;
}
}
}
main()
{
cin >> n >> q;
for(int i = 2; i <= n; i++) cin >> fa[i], add(fa[i], i);
dfs1(1); dfs2(1);
while(q--)
{
int t; cin >> t;
cout << ans[t] << endl;
}
}

浙公网安备 33010602011771号