题目链接:Codeforces - On Changing Tree
子树操作,比较显然的dfs序。
我们看一下子树根对其他点的影响或贡献:x-(dep[v]-dep[u])*k
然后拆开:x-dep[v]*k+dep[u]*k
当我们操作根的时候,只要根定了,那么dep[u]*k就是一个定值。看成x的一部分。
所以我们用两个lazy维护x和k即可。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+10,mod=1e9+7;
int n,q,st[N],ed[N],cnt,dep[N],dfn[N];
vector<int> g[N];
void dfs(int x,int fa){
st[x]=++cnt; dfn[cnt]=x; dep[x]=dep[fa]+1;
for(auto to:g[x]) if(to!=x) dfs(to,x);
ed[x]=cnt;
}
int ls[N<<2],lk[N<<2];
inline void push_down(int p){
ls[p<<1]=(ls[p<<1]+ls[p])%mod,ls[p<<1|1]=(ls[p<<1|1]+ls[p])%mod;
lk[p<<1]=(lk[p<<1]+lk[p])%mod,lk[p<<1|1]=(lk[p<<1|1]+lk[p])%mod;
ls[p]=lk[p]=0;
}
void change(int p,int l,int r,int ql,int qr,int k,int s){
if(l==ql&&r==qr){
ls[p]=(ls[p]+s)%mod; lk[p]=(lk[p]+k)%mod; return ;
}
int mid=l+r>>1; push_down(p);
if(qr<=mid) change(p<<1,l,mid,ql,qr,k,s);
else if(ql>mid) change(p<<1|1,mid+1,r,ql,qr,k,s);
else change(p<<1,l,mid,ql,mid,k,s),change(p<<1|1,mid+1,r,mid+1,qr,k,s);
}
int ask(int p,int l,int r,int x){
if(l==r) return (ls[p]-dep[dfn[l]]*lk[p]%mod+mod)%mod;
int mid=l+r>>1; push_down(p);
if(x<=mid) return ask(p<<1,l,mid,x);
else return ask(p<<1|1,mid+1,r,x);
}
signed main(){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
cin>>n;
for(int i=2,x;i<=n;i++) cin>>x,g[x].push_back(i);
dfs(1,1); cin>>q;
for(int i=1,op,v,x,k;i<=q;i++){
cin>>op>>v;
if(op==1) cin>>x>>k,change(1,1,n,st[v],ed[v],k,x+dep[v]*k);
else cout<<ask(1,1,n,st[v])<<'\n';
}
return 0;
}