题意:一棵树只有一个顶点,然后由这个顶点引申出多条单链,对于输入 0 v x d,代表把距离V节点距离在d以内的所有节点增加x,对于输入 1 v,代表查询v节点的值;
解题:对根节点和根节点的所有孩子节点建一棵树状数组,树状数组下标为深度,用前缀和表示每个节点的值,在单个节点更新变化,即如在(2,5)区间加5,则位置2要+5,位置6要-5;
然后要考虑是否跨根的情况,如果跨根就把影响直接更新到根的树状数组上,这样查询的时候就要同时查节点u的顶节点的树和根节点的树,同时更新时主要消除根节点的树和子节点的树的重复添加的情况。然后根节点的值就直接单独统计就好。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
#define ls rt<<1
#define rs rt<<1|1
#define lowbit(x) (x&(-x))
const int maxn=600000;
const int maxm=600000;
struct node
{
int u,v,next;
}edge[maxm];
//初始值都为0
struct BIT
{
vector<int>b;
int n;
void init()
{
for(int i=1;i<=n;i++)
b.push_back(0);
}
int getsum(int pos)
{
int tmp=0;
for(int i=pos; i>0; i-=lowbit(i))
tmp+=b[i-1];
return tmp;
}
int update(int pos,int val)
{
// cout<<pos<<" update "<<val<<endl;
for(int i=pos; i<=n; i+=lowbit(i))
b[i-1]+=val;//cout<<i<<" hou "<<b[i]<<endl;
}
} B[maxn];
int em;
int head[maxn];
void init()
{
em=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v)
{
edge[em].u=u;
edge[em].v=v;
edge[em].next=head[u];
head[u]=em++;
}
int dep[maxn];
int top[maxn];
void dfs(int x,int fa,int depth,int root)
{
dep[x]=depth;
top[x]=root;
B[root].n=max(B[root].n,depth);
B[1].n=max(B[1].n,depth);
for(int i=head[x]; ~i; i=edge[i].next)
{
int v=edge[i].v;
if(v==fa) continue;
dfs(v,x,depth+1,root);
}
}
int val[10];
void update(int v,int x,int d)
{
int dis=dep[v];
//bu guo geng
int root=top[v];
if(dis>d)
{
B[root].update(dep[v]-d,x);
if(dep[v]+d+1<=B[root].n)B[root].update(dep[v]+d+1,-x);//cout<<root<<" root"<<endl;//??
}
else//guo geng
{
val[1]+=x;//geng xin geng的值
B[root].update(1,x);//cout<<root<<" root"<<endl;
if(dep[v]+d+1<=B[root].n) {B[root].update(dep[v]+d+1,-x);}//和总长度取min值
B[1].update(1,x);//cout<<1<<" root"<<endl;
// cout<<(dis-d+1)<<" "<<dis<<" "<<d<<" "<<B[1].n<<endl;
if(d-dis+1<=B[1].n) B[1].update(d-dis+1,-x);//cout<<1<<" root"<<endl;
//这里要消除自己的yingxiang
B[root].update(1,-x);
if(d-dis+1<=B[root].n) B[root].update(d-dis+1,+x);
}
}
int query(int x)
{
if(x==1) return val[1];
int dis=dep[x];
int tmp1=B[1].getsum(dis);
int tmp2=B[top[x]].getsum(dis);
// cout<<tmp1<<" query "<<tmp2<<endl;
return tmp1+tmp2;
}
int op,u,v,x,d,n,q;
void work()
{
dep[1]=0;
for(int i=1;i<=n;i++)
B[i].n=0;
memset(top,0,sizeof(top));
for(int i=head[1]; ~i; i=edge[i].next)
{
int v=edge[i].v;
dfs(v,1,1,v);
}
for(int i=1;i<=n;i++)
B[i].b.clear(),B[i].init();
// for(int i=1;i<=n;i++)
// cout<<B[i].n<<" "<<i<<endl;
for(int i=1; i<=q; i++)
{
scanf("%d",&op);
if(op==0)
{
scanf("%d%d%d",&v,&x,&d);//v d范围内加x
update(v,x,d);
}
else
{
scanf("%d",&v);
printf("%d\n",query(v));
}
}
}
//二维,树状数组维护变化,前缀和维护值
int main()
{
while(scanf("%d%d",&n,&q)!=EOF)
{
init();
val[1]=0;
for(int i=1; i<=n-1; i++)
scanf("%d%d",&u,&v),addedge(u,v),addedge(v,u);
work();
// cout<<"over"<<endl;
}
return 0;
}