思路:
dfs序建树把树结构转换成线性结构,然后变成单点修改加区间查询
dfs序建树:
dfs遍历所有节点 ,l数组记录开始递归时间,r数组记录结束递归时间,这样 l 和 r之间就包含了所有 该节点的子节点,如下图:
代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=1e6+7;
ll n,m,head[maxn],num=0,root;
ll ans,val[maxn],sum[maxn<<2];
struct node{
int next,to;
};
struct node edge[maxn<<1];
void add(int u,int v){
edge[num].next=head[u];
edge[num].to=v;
head[u]=num++;
}
int cnt,l[maxn],r[maxn];
void dfs(int u, int pre){
l[u]=++cnt;
for(int i = head[u]; i != -1; i = edge[i].next){
int to = edge[i].to;
if(to == pre) continue;
dfs(to, u);
}
r[u]=cnt;
}
void pushup(ll rt){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update1(ll i,ll c,ll l,ll r,ll rt){
if(l==r) {
sum[rt]+=c;
return;
}
ll m=(l+r)>>1;
if(i<=m) update1(i,c,l,m,rt<<1);
else update1(i,c,m+1,r,rt<<1|1);
pushup(rt);
}
ll query(ll L,ll R,ll l,ll r,ll rt){
ll s=0;
if(L<=l&&R>=r) return sum[rt];
ll m=(l+r)>>1;
if(L<=m) s+=query(L,R,l,m,rt<<1);
if(R>m) s+=query(L,R,m+1,r,rt<<1|1);
return s;
}
int main (){
int n,m,k,u,v;
cin>>n>>m>>root;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++) scanf("%lld",&val[i]);
for(int i=0;i<n-1;i++){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs(root,-1);
for(int i=1;i<=n;i++) update1(l[i],val[i],1,n,1);
for(int i=0;i<m;i++){
ll x,a,b;
scanf("%lld",&x);
if(x==1){
scanf("%lld%lld",&a,&b);
update1(l[a],b,1,n,1);
}
else{
scanf("%lld",&a);
printf ("%lld\n",query(l[a],r[a],1,n,1));
}
}
}