牛客——求和(dfs序+树状数组)
原题链接
题意:
给定一棵树,有点权;两种操作,一是修改某个单点的权值,二是查询某个点为根节点的子树的点权之和。
思路:
dfs序后,子树都处于一个区间里,所以问题就转化成了单点修改、区间求和。
用树状数组维护即可。
代码:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int maxn=1e6+7;
int n,m,k;
int h[maxn],idx;
struct node{
int e,ne;
}edge[maxn*2];
ll w[maxn],tr[maxn*4];
void add(int u,int v){///前向星存图
edge[idx]={v,h[u]};h[u]=idx++;
}
ll in[maxn],out[maxn],timetmp;
void dfs(int u,int fa){//dfs记录dfs序列
in[u]=++timetmp;
for(int i=h[u];~i;i=edge[i].ne){
int j=edge[i].e;
if(j==fa) continue;
dfs(j,u);
}
out[u]=timetmp;
}
///树状数组维护区间
ll lowbit(int x){
return x&(-x);
}
void update(int pos,int val){
while(pos<maxn){
tr[pos]+=val;
pos=pos+lowbit(pos);
}
}
ll qask(int pos){
ll res=0;
while(pos){
res+=tr[pos];
pos=pos-lowbit(pos);
}
return res;
}
int main(){
cin>>n>>m>>k;
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++) cin>>w[i];
for(int i=1;i<n;i++){
ll u,v;
cin>>u>>v;
add(u,v);add(v,u);
}
dfs(k,-1);
for(int i=1;i<=n;i++)
update(in[i],w[i]);
while(m--){
int op;cin>>op;
if(op==1){
ll pos,x;
cin>>pos>>x;
update(in[pos],x);
}
else{
int pos;cin>>pos;
printf("%lld\n",qask(out[pos])-qask(in[pos]-1));
}
}
return 0;
}