CF860E Arkady and a Nobody-men 题解
感觉很牛啊,算是一道并不模板的长剖优化 dp 好题了。
先考虑编一个暴力 dp。显然可以设
其中
现在考虑怎么求
考虑如何优化。我们把转移
一个观察是对于同一层的所有
具体地,对于节点
同时让
::::info[code]
#include <bits/stdc++.h>
#define ll long long
using namespace std;
constexpr int N = 5e5 + 5;
int n, rt;
int fa[N], dep[N], h[N], son[N];
ll ans[N];
vector<int> e[N];
vector<array<ll, 2>> E[N];
int buf1[N], *p1 = buf1, *p[N];
int buf2[N], *p2 = buf2, *cnt[N];
void dfs1(int u) {
h[u] = 1;
dep[u] = dep[fa[u]] + 1;
for (auto v : e[u]) {
dfs1(v);
h[u] = max(h[u], h[v] + 1);
if (h[v] > h[son[u]]) son[u] = v;
}
}
void dfs2(int u, int tp) {
if (u == tp) {
p[u] = p1;
p1 += h[u];
cnt[u] = p2;
p2 += h[u];
}
if (son[u]) {
p[son[u]] = p[u] + 1;
cnt[son[u]] = cnt[u] + 1;
dfs2(son[u], tp);
}
p[u][0] = u, cnt[u][0] = 1;
for (auto v : e[u]) {
if (v == son[u]) continue;
dfs2(v, v);
for (int i = 0; i < h[v]; ++i) {
ans[p[u][i + 1]] += 1ll * dep[u] * cnt[v][i];
ans[p[v][i]] += 1ll * dep[u] * cnt[u][i + 1];
E[p[u][i + 1]].push_back({p[v][i], ans[p[v][i]] - ans[p[u][i + 1]]});
cnt[u][i + 1] += cnt[v][i];
}
}
}
void dfs3(int u, bool flag) {
if (flag && son[u]) {
dfs3(son[u], flag);
}
for (auto cur : E[u]) {
ans[cur[0]] = ans[u] + cur[1];
dfs3(cur[0], false);
}
}
void dfs4(int u) {
for (auto v : e[u]) {
ans[v] += ans[u] + dep[u];
dfs4(v);
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> fa[i];
if (fa[i] > 0) {
e[fa[i]].push_back(i);
} else {
rt = i;
}
}
dfs1(rt);
dfs2(rt, rt);
dfs3(rt, true);
dfs4(rt);
for (int i = 1; i <= n; ++i) {
cout << ans[i] << " \n"[i == n];
}
return 0;
}
::::