P13663 「TPOI-5B」回忆
- \(f_u\) 其实就是 \(u\) 子树的深度。
- 每次加入一个点 \(u\),\(f\) 会加 \(1\) 的那些点形如 \(i\) 往上的一条链 \(u\to anc_u\)——其中 \(anc\) 需要我们求出。
- 其它点的 \(f\) 不变。
考虑离线把树建出来,并尝试计算 \(anc\)。
对于点 \(u\) 来说,其祖先 \(v\in \text{path}(i\to anc_u)\) 当且仅当 \(u\) 是 \(v\) 子树里同深度最小点。
故而考虑维护 \(pos_{u,i}\) 表示 \(u\) 子树里,距离 \(u\) 为 \(i\) 的最小编号点。长链剖分维护即可。
点击查看代码
#include <bits/stdc++.h>
#define FL(i, a, b) for (int i = (a); i <= (b); ++i)
#define FR(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
typedef long long ll;
const int N = 5e6 + 10, MOD = 1e9 + 7;
int n, q, a[N], fa[N], mxD[N], son[N];
int buc[N], *bid = buc, *pos[N];
ll ans[N], val[N];
vector<int> G[N];
void Dfs1(int u) {
val[u] = val[fa[u]] + a[u];
for (int v: G[u]) {
Dfs1(v);
if (mxD[v] > mxD[son[u]])
son[u] = v;
}
mxD[u] = mxD[son[u]] + 1;
}
int* NewArr(int len) {
int* ret = bid;
return bid += len, ret;
}
void Dfs2(int u) {
pos[u][0] = u;
if (son[u]) {
pos[son[u]] = pos[u] + 1;
Dfs2(son[u]);
}
for (int v: G[u]) {
if (v != son[u]) {
pos[v] = NewArr(mxD[v]);
Dfs2(v);
FL(i, 0, mxD[v] - 1) {
int &x = pos[u][i + 1];
int &y = pos[v][i];
if (x > y) swap(x, y);
ans[y] += val[fa[y]] - val[u];
}
}
}
}
int main() {
scanf("%d %d", &q, &a[1]), n = q + 1;
FL(i, 2, q + 1) {
scanf("%d %d", &fa[i], &a[i]);
G[fa[i]].emplace_back(i);
}
Dfs1(1);
pos[1] = NewArr(mxD[1]);
Dfs2(1);
FL(i, 0, mxD[1] - 1) {
int x = pos[1][i];
ans[x] += val[fa[x]];
}
FL(i, 2, q + 1) {
ans[i] += ans[i - 1];
printf("%lld\n", ans[i] %= MOD);
}
return 0;
}