树上差分 - 树上操作 题解
原题
有一个
一个节点的深度定义为其父节点的深度
现在需要支持一系列以下操作:给节点
问完成所有操作后,各节点的权值是多少。
思路
本题使用离线算法,首先记录所有更新数据。
然后用 dfs(x) 表示正在更新以
如果当前点
s[l]+=d;
s[r+1]-=d;
因为我们在枚举
所以我们差分时,感觉要维护单点修改,区间查询
是不是要用 BIT(树状数组)呢?答案显然是否定的。
其实只要写一个差分数组,在 dfs 的时候顺带着求和即可。
这时候就只用
总时间复杂度为
但由于数据较为毒瘤,另设有多组 hack 数据,所以,该题必须要用链式前向星和适当的输入优化来卡常。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 7, M = 1e9 + 7, ma = 12347;
#define int long long
int l[N], r[N], d[N], n, q, x, ans[N], a[N], h;
vector<int> g[N], v[N];
void dfs(int x, int dep, int z) {
for (int i = 0; i < v[x].size(); ++i) {
int y = v[x][i];
if (r[y] < dep)
continue;
if (l[y] < dep)
l[y] = dep;
a[l[y]] += d[y];
a[r[y] + 1] -= d[y];
}
z += a[dep];
ans[x] = z;
for (int i = 0; i < g[x].size(); ++i) dfs(g[x][i], dep + 1, z);
for (int i = 0; i < v[x].size(); ++i) {
int y = v[x][i];
if (r[y] < dep)
continue;
a[l[y]] -= d[y];
a[r[y] + 1] += d[y];
}
}
signed main() {
scanf("%lld", &n);
for (int i = 2; i <= n; ++i) {
scanf("%lld", &x);
g[x].push_back(i);
}
scanf("%lld", &q);
for (int i = 1; i <= q; ++i) {
scanf("%lld%lld%lld%lld", &x, l + i, r + i, d + i);
v[x].push_back(i);
}
dfs(1, 1, 0);
for (int i = 1; i <= n; ++i) h = (h * ma + ans[i]) % M;
//本题采用 hash 的方式生成数据,实际和直接输入是一样的
printf("%lld\n", h);
return 0;
}