阔力梯的树
题面
题解
树上问题, 树链剖分, lca变成线性, 点分治, 点分树, dsu on tree
这道题是 dsu on tree, 还是要用时间戳这个好东西, 可以维护子树
然后就是加子树入编号影响的问题, 用set维护就好了
int n, m, _, k, cas;
VI h[N];
int dfn[N], low[N], df, son[N], sz[N], rk[N];
ll ans[N], sum;
set<int> st;
void dfs(int x) {
rk[dfn[x] = ++df] = x, sz[x] = 1;
for (auto &y : h[x]) {
dfs(y); sz[x] += sz[y];
if (!son[x] || sz[y] > sz[son[x]]) son[x] = y;
}
low[x] = df;
}
void add(ll x) {
if (st.empty()) { st.insert(x); return; }
auto it = st.lower_bound(x);
if (it == st.begin()) sum += sqr(x - *it), st.insert(x);
else if (it == st.end()) --it, sum += sqr(x - *it), st.insert(x);
else {
ll cur = *it; sum += sqr(x - cur); --it;
sum += sqr(x - *it) - sqr(*it - cur); st.insert(x);
}
}
void dsu(int x, bool f) {
for (auto &y : h[x]) if (y ^ son[x]) dsu(y, 0);
if (son[x]) dsu(son[x], 1);
for (auto &y : h[x]) if (y ^ son[x]) rep (j, dfn[y], low[y]) add(rk[j]);
add(x); ans[x] = sum;
if (!f) clear(st), sum = 0;
}
int main() {
IOS; cin >> n;
rep (i, 2, n) cin >> m, h[m].pb(i);
dfs(1); dsu(1, 0);
rep (i, 1, n) cout << ans[i] << '\n';
return 0;
}