题意: 给你一棵树,有两种操作: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; }