题意: 给你一棵树,有两种操作:1.更新点v,离v点d距离内的所有点都增加x。2.查询v点的值。
思路: 题目有个特点,就是每个节点的度小于等于2(除了根1以外),这里的度不是树中的度,是图论里度的定义。也就是说去掉根节点1,剩下的就是许多条链。那么可以每条链维护一个BIT。同时在d距离内从v点出发有可能到达别的链,我们还要更新别的链。但如果一条一条去更新,会有超时。我们可以先从v出发,走到根1,然后从根1走完剩下的距离。从跟1出发,d距离内能走到哪些点,只和这个点所在的层数有关,只要它的层数小于等于d+1那么就一定能从根1走到它。所以我们再建一个维护树层的BIT,用于更新从v点出发走到别的链。最后对于v的答案就是层+所在链。
代码:
#include<iostream>
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<string.h>
using namespace std;
#define N 100010
//从左到右4个数组依次表示:
//v点所在链的编号,所在层数,v在链上标号,各条链长度。
int mark[N],level[N],pos[N],length[N],id,deep;
vector<int> e[N];
class BIT{
private:
int *sum,n;
public:
void init(int _n)
{
n=_n;
sum=new int[n+1];
memset(sum,0,(n+1)*sizeof(int));
}
int query(int i)
{
int ans=0;
for(;i<=n;i+= i&-i)
ans+=sum[i];
return ans;
}
void add(int i,int x)
{
for(;i>0;i-= i&-i)
sum[i]+=x;
}
void update(int l,int r,int x)
{
add(r,x);
add(l-1,-x);
}
}tree,*chain;
int dfs(int step,int u,int pre)
{
int i,n=e[u].size(),v;
level[u]=step+1;
mark[u]=id;
pos[u]=step;
for(i=0;i<n;i++){
v=e[u][i];
if(v==pre) continue;
return dfs(step+1,v,u);
}
return step;
}
void pretreat()
{ //预处理出每个点在哪条链,在链上的编号等信息
int i,n=e[1].size(),len,v;
chain=new BIT[n];
level[1]=1;
for(i=0;i<n;i++){
id=i;
v=e[1][i];
len=dfs(1,v,1);
length[i]=len;
deep=max(len,deep);
chain[i].init(len);
}
tree.init(++deep);
}
int query(int v)
{
int ans=0;
ans=tree.query(level[v]);
if(v!=1){
ans+=chain[mark[v]].query(pos[v]);
}
return ans;
}
void update(int v,int x,int d)
{
int l,r;
if(v==1){
if(deep>=1+d) r=1+d;
else r=deep;
tree.update(1,r,x);
return ;
}
if(length[mark[v]]>=pos[v]+d) r=pos[v]+d;
else r=length[mark[v]];
if(1<=pos[v]-d) l=pos[v]-d;
else l=1;
chain[mark[v]].update(l,r,x);
d-=level[v]-1;
if(d>=0){
if(deep>=1+d) r=1+d;
else r=deep;
tree.update(1,r,x);
if(r>=2){
if(length[mark[v]]>=r-1) r=r-1;
else r=length[mark[v]];
chain[mark[v]].update(1,r,-x);
}
}
}
int main()
{
int i,n,q,x,y;
scanf("%d %d",&n,&q);
for(i=0;i<n-1;i++){
scanf("%d %d",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
}
pretreat(); //预处理
int op,v,d;
while(q--){
scanf("%d %d",&op,&v);
if(op){
printf("%d\n",query(v));
}else{
scanf("%d %d",&x,&d);
update(v,x,d);
}
}
return 0;
}