Solution
每个子树都对应DFS序上的一段区间。
发现所有操作要么只针对子树,要么只针对单个节点,因此我们可以利用DFS序将树上的操作转化为区间上的操作。
当我们更新节点 \(u\) 时,对于他的子节点 \(i\),它的变化值为\(x-(dep[i]-dep[u])*k=x+dep[u]*k-dep[i]*k\),我们只用记录\(x+dep[u]*k\)和\(k\),最后就能算出答案。
用树状数组优化一下就过了。
因为树状数组或线段树的特性,想要利用它们优化区间更新,就需要找到该区间内每个元素相同的变化量。
Code:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 10;
const int MOD = 1e9 + 7;
vector<int> e[MAXN];
long long c1[MAXN],c2[MAXN],n,q,siz[MAXN],dep[MAXN],num[MAXN],cnt;
inline int lowbit(int x) {
return (x & -x);
}
void update(long long x,long long val,long long k) {
for (int i = x; i <= n; i += lowbit(i)) {
c1[i] = (c1[i] + val) % MOD;c2[i] = (c2[i] + k) % MOD;
}
}
long long query(int x,int u) {
int sum1 = 0,sum2 = 0;
for (int i = x; i > 0; i -= lowbit(i)) {
sum1 = (sum1 + c1[i]) % MOD;sum2 = (sum2 + c2[i]) % MOD;
}
return ((sum1 - dep[u] * sum2) % MOD + MOD) % MOD;
}
void DFS(int u,int fa) {
num[u] = ++cnt;
int len = e[u].size();dep[u] = dep[fa] + 1;siz[u] = 1;
for (int i = 0; i < len; i++) {
DFS(e[u][i],u);
siz[u] += siz[e[u][i]];
}
return;
}
int main() {
scanf("%d",&n);
for (int i = 2; i <= n; i++) {
int u;
scanf("%d",&u);
e[u].push_back(i);
}
DFS(1,0);
scanf("%d",&q);
for (int i = 1; i <= q; i++) {
int type;scanf("%d",&type);
if (type == 1) {
long long u,x,k;
scanf("%lld%lld%lld",&u,&x,&k);
update(num[u],(x + dep[u] * k) % MOD,k);
update(num[u] + siz[u],-(x + dep[u] * k) % MOD,-k);
}
if (type == 2) {
int u;
scanf("%d",&u);
printf("%lld\n",query(num[u],u));
}
}
return 0;
}