题目链接:https://cn.vjudge.net/problem/FZU-2277
题意:
1 v x k : a[v]+=x , a[v’]+=x-k (v’ is child of v) , a[v’’]+=x-2*k (v’’ is child of v’) and so on.
2 v : Output a[v] mod 1000000007(10^9 + 7).
错误思路:
我们把点权分成两部分,一部分是x,一部分是k。那么用dfs序可以解决x的修改,然后发现k值修改很难维护,因为涉及到了深度差,子树的各点距根不同,所以增加的值也不同,不好直接进行区间修改。
想了很长时间只想到一个O(n*(层数))的做法,dfs序区间修改解决x。对于k值,当查询一个点v时,就往上走到根,判断它的祖先是否被1操作修改了,如果被修改了,那么根据层数差 和 修改的值来更新v的值。
这样的话数据随机生成的话才能通过。
正确思路:
将修改的子树根记录为 u ,子树上的点记录为v。记s[i]为第i个点的点权。
那么每次修改可以表示为:
s[v] += x - (dis[v]-dis[u])*k;
既 s[v] += x+dis[u]*k - dis[v] * k;
然后可以发现,对于确定的子树而言x+dis[u]*k是一个常数,可以用区间修改(树状数组差分)处理。
对于后半部分,k值也可以用另一个树状数组处理,然后统计的时候再乘上当前点的深度就可以了。
比赛的时候两部分的值考虑到分开处理了,但是并没有尝试对式子进行变形。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
//#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a);i <= (b); i++)
#define mp make_pair
#define pb push_back
#define ll long long
#define pli pair<long long,int>
#define all(x) (x).begin(),(x).end()
using namespace std;
const int mod = 1e9+7;
const int N = 3e5+1000;
vector<int>nxt[N];
int in[N],out[N],tot;
ll tree[N],tree2[N],dis[N];
int lb(int x) {
return x&-x;
}
void add(ll* tree,int x,ll data) {
data = ((data%mod)+mod)%mod;
while(x<N-500) {
tree[x] += data;
x+=lb(x);
}
}
ll que(ll *tree,int x) {
ll ans = 0;
while(x>0) {
ans += tree[x];
ans %= mod;
x -= lb(x);
}
return ans;
}
void dfs(int u) {
in[u] = ++tot;
int siz = nxt[u].size();
rep(i, 0, siz-1) {
int v = nxt[u][i];
dis[v] = dis[u]+1;
dfs(v);
}
out[u] = tot;
}
void init(int n) {
tot = 0;
rep(i, 1, n) nxt[i].clear();
dis[1] = 0;
memset(tree,0,sizeof(tree));
memset(tree2,0,sizeof(tree2));
}
int main() {
//freopen("a.txt","r",stdin);
ios::sync_with_stdio(0);
int T;
cin>>T;
while(T--) {
int n;
cin>>n;
init(n);
rep(i, 2, n) {
int x;
cin>>x;
nxt[x].pb(i);
}
dfs(1);
int q;
cin>>q;
rep(i, 1, q) {
int oper, u;
cin>>oper;
if(oper==1) {
ll x,k;
cin>>u>>x>>k;
add(tree,in[u],x+dis[u]*k);
add(tree,out[u]+1,-dis[u]*k-x);
add(tree2,in[u],-k);
add(tree2,out[u]+1,k);
}
else {
cin>>u;
ll ans = que(tree,in[u]);
ans += que(tree2,in[u])*dis[u];
ans = ((ans%mod)+mod)%mod;
cout<<ans<<endl;
}
}
}
return 0;
}