E:
树的启发式合并。
子树的节点编号排序后的序列为,这个节点的“结实程度”就是:
求每个节点的“结实程度”。
首先一遍dfs处理出每个节点的子树大小。
然后再dfs,从叶节点开始合并子树信息。
考虑将每个节点开一个set,然后不断插入,这里有一个优化,父节点的set初值为子树最大的子节点的set值。
最后不要忘记把父节点插入set中。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<set> using namespace std; typedef long long ll; const int MAXN = 4000009 + 111; vector<int>G[MAXN]; int fa[MAXN],sz[MAXN]; ll a[MAXN]; int n; void dfs1(int x) { sz[x] = 1; for(int i = 0;i < G[x].size();i ++){ int v = G[x][i]; if(v == fa[x]) continue; dfs1(v); sz[x] += sz[v]; } return; } set<int>dfs(int x){ set<int>S; if(sz[x] == 1){ S.insert(x); return S; } ll ans = 0; int pos = 0,Max = -1; for(int i = 0;i < G[x].size();i ++) if(sz[G[x][i]] > Max && G[x][i] != fa[x]) Max = sz[G[x][i]],pos = G[x][i]; S = dfs(pos); ans = a[pos]; set<int>::iterator f = S.lower_bound(x); if(f == S.begin()) ans += 1LL * (*f - x) * (*f - x); else if(f == S.end()) f --,ans += 1LL * (x - *f) * (x - *f); else { int t1 = *f,t2; f --,t2 = *f; ans -= 1LL * (t1 - t2) * (t1 - t2); ans += 1LL * (x - t2) * (x - t2) + 1LL * (t1 - x) * (t1 - x); } S.insert(x); for(int i = 0;i < G[x].size();i ++){ int v = G[x][i]; if(v == fa[x] || v == pos) continue; set<int>SS = dfs(v); for(set<int>::iterator it = SS.begin();it != SS.end();it ++){ set<int>::iterator f = S.lower_bound(*it); if(f == S.begin()) ans += 1LL * (*f - *it) * (*f - *it); else if(f == S.end()) f --,ans += 1LL * (*it - *f) * (*it - *f); else { int t1 = *f,t2; f --,t2 = *f; ans -= 1LL * (t1 - t2) * (t1 - t2); ans += 1LL * (*it - t2) * (*it - t2) + 1LL * (t1 - *it) * (t1 - *it); } S.insert(*it); } } a[x] = ans; return S; } void solve(){ cin >> n; for(int i = 2;i <= n;i ++){ scanf("%d",&fa[i]); G[fa[i]].push_back(i); G[i].push_back(fa[i]); } dfs1(1); dfs(1); for(int i = 1;i <= n;i ++) printf("%lld\n",a[i]); } int main(){ solve(); return 0; }