题意:
解法:
一个关键信息:
除了点1以外,每个点的度数<=2,这意味着整棵树其实就是若干条从点1延伸出来的链.
由于是链,我们先求出每个点的dfs序,那么同一条链上的点就变成连续区间了.
设现在要将对于同一点x,距离<=d的所有点权加上val,
1.如果被增加的点在同一条链上,那么直接线段树上区间修改即可.
2.如果被增加的点越过了点1,那么被增加点权的点,会是以点1为中心的一个扇形,
另开一棵线段树,维护深度=x的点被加了多少点权即可.
对于查询操作,将两颗线段树上查出来的值加起来就是答案.
ps:
代码实现中还有一些需要讨论的细节,这里就不细说了.
code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxm=1e5+5;
struct Tree{
int laz[maxm<<2];
void pd(int node){
if(laz[node]){
laz[node*2]+=laz[node];
laz[node*2+1]+=laz[node];
laz[node]=0;
}
}
void add(int st,int ed,int val,int l,int r,int node){
if(st<=l&&ed>=r){
laz[node]+=val;
return ;
}
pd(node);
int mid=(l+r)/2;
if(st<=mid)add(st,ed,val,l,mid,node*2);
if(ed>mid)add(st,ed,val,mid+1,r,node*2+1);
}
int ask(int x,int l,int r,int node){
if(l==r)return laz[node];
pd(node);
int mid=(l+r)/2;
if(x<=mid)return ask(x,l,mid,node*2);
else return ask(x,mid+1,r,node*2+1);
}
}T1,T2;
int L[maxm],R[maxm],idx;
int dep[maxm],top[maxm];
vector<int>g[maxm];
int n,q;
void dfs(int x,int fa,int tp){
L[x]=++idx;
if(fa==1)tp=L[x];
dep[x]=dep[fa]+1;top[x]=tp;
for(int v:g[x]){
if(v==fa)continue;
dfs(v,x,tp);
}
R[x]=idx;
}
void solve(){
cin>>n>>q;
for(int i=1;i<n;i++){
int a,b;cin>>a>>b;
g[a].push_back(b);
g[b].push_back(a);
}
dfs(1,1,1);
while(q--){
int op;cin>>op;
if(op==0){
int x,val,d;cin>>x>>val>>d;
if(x==1){
T2.add(1,d+1,val,1,n,1);
}else if(dep[x]>=d+1){
int l=max(top[x],L[x]-d);
int r=min(R[x],L[x]+d);
T1.add(l,r,val,1,n,1);
if(dep[x]==d+1){
T1.add(1,1,val,1,n,1);
}
}else if(dep[x]<d+1){
int l=max(top[x],L[x]-d);
int r=min(R[x],L[x]+d);
T1.add(l,r,val,1,n,1);
T1.add(1,1,val,1,n,1);
int rem=d-(dep[x]-1);
T2.add(1,rem+1,val,1,n,1);
T1.add(1,1,-val,1,n,1);
int lc=top[x];
int rc=min(R[x],top[x]+(rem-1));
if(lc<=rc)T1.add(lc,rc,-val,1,n,1);
}
}else if(op==1){
int x;cin>>x;
int ans=T1.ask(L[x],1,n,1)+T2.ask(dep[x],1,n,1);
cout<<ans<<endl;
}
}
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
solve();
return 0;
}