题目大意:对于一个有根树有n个结点,每个结点上都有权值。一共有q次操作,分别为以下两种:
1.将以结点i为根的子树除i之外的点的重要度增加delta
2.询问当前点重要度。
数据范围:n<=5*10^5,q<=10^6,delta<=10^3
对于30%的数据n<=500,q<=1000.
对于30%的数据,直接模拟在树上的修改即可,最坏情况单次修改达到O(n)
本题中,要修改一棵子树上的所有值,于是想到与区间有关的问题。如何把树转为区间呢?可以先预处理,DFS遍历这棵树,记录遍历序,这样就转成区间了。因为要修改子树上的值,于是可以记录入栈序,这样处理就可以把一个结点子树变成一段连续的区间。区间修改单点查询用树状数组或线段树均可。
#include <cstdio>
#include <cstring>
using namespace std;
struct Edge{
int from,to,nex;
}e[500010];
struct Segment_Tree{
int l,r,add,v;
}st[2000010];
struct Node{
int val,pos,l,r;
}a[500010];
int n,fir[500010],m,sta[500010],top,pa[500010];
void init(int,int,int);
void dfs(int);
int query(int,int);
void push_down(int);
void change(int,int,int,int);
int root(int);
int main(){
freopen("chinese.in","r",stdin);
freopen("chinese.out","w",stdout);
scanf("%d%d",&n,&m);
memset(fir,-1,sizeof fir);
scanf("%d",&a[1].val);
for(int i=1;i<=n;i++) pa[i]=i;
for(int i=2;i<=n;i++) {
int x;
scanf("%d%d",&a[i].val,&x);
pa[i]=root(x);
e[i].from=x; e[i].to=i;
e[i].nex=fir[x]; fir[x]=i;
}
dfs(1);
init(1,1,n);
while(m--){
char mode[3];
int x,y;
scanf("%s",mode);
scanf("%d",&x);
if(mode[0]=='u') {
if(root(x)==1) printf("%d\n",query(1,a[x].pos));
else printf("0\n");
}
else { scanf("%d",&y); change(1,a[x].l,a[x].r,y); }
}
fclose(stdin); fclose(stdout);
return 0;
}
void init(int x,int l,int r){
st[x].l=l; st[x].r=r;
if(l==r) { st[x].v=a[sta[l]].val; return; }
int mid=(l+r)>>1;
init(x<<1,l,mid); init((x<<1)+1,mid+1,r);
return ;
}
void dfs(int x){
sta[++top]=x;
a[x].pos=top;
a[x].l=top+1;
for(int i=fir[x];i!=-1;i=e[i].nex) dfs(e[i].to);
a[x].r=top;
return;
}
int query(int x,int pos){
if(st[x].l==pos && st[x].r==pos) return st[x].v+st[x].add;
if(st[x].add) push_down(x);
int mid=(st[x].l+st[x].r)>>1;
if(pos<=mid) return query(x<<1,pos);
return query((x<<1)+1,pos);
}
void push_down(int x){
st[x<<1].add+=st[x].add;
st[(x<<1)+1].add+=st[x].add;
st[x].add=0;
return;
}
void change(int x,int l,int r,int v){
if(l>r) return;
if(st[x].add && st[x].l!=st[x].r) push_down(x);
if(st[x].l==l && st[x].r==r) { st[x].add+=v; return; }
int mid=(st[x].l+st[x].r)>>1;
if(r<=mid) change(x<<1,l,r,v);
else if(l>mid) change((x<<1)+1,l,r,v);
else change(x<<1,l,mid,v),change((x<<1)+1,mid+1,r,v);
return;
}
int root(int x){return pa[x]==x ? pa[x] : root(pa[x]); }