牛客小白月赛24 I.求和 (数状数组&DFS序)
思路:单点修改和区间查询。用DFS序形成一个数组。再用树状数组求和和更新。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int tr[N],n,m,k,a[N],in[N],out[N],tot;//tr[](tree[]数状数组) in[] out[]分别代表入栈,出栈时间.
typedef long long ll;
#define lowbit(x) (x&-x)
vector<int>e[N];
int read(){ //快读
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void upd(int i,int x){//更新.
while(i<=n){
tr[i]+=x;
i+=lowbit(i);
}
}
ll sum(int i){ //求和
ll sum=0;
while(i) sum+=tr[i],i-=lowbit(i);
return sum;
}
void dfs(int u,int fa){ //求dfs序
in[u]=++tot,upd(tot,a[u]);
for(auto v:e[u]){
if(v!=fa) dfs(v,u);
}
out[u]=tot;
}
int main(){
n=read(),m=read(),k=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1,u,v;i<n;i++){
u=read(),v=read();
e[u].push_back(v),e[v].push_back(u);
}
dfs(k,0);
while(m--){
int op,a,x;
op=read(),a=read();
if(op==1) x=read(),upd(in[a],x);//这里数状数组下标是in[a]
else printf("%lld\n",sum(out[a])-sum(in[a]-1));//区间和(类似前缀和求法)
}
return 0;
}
补充:update原理:由左儿子向根扩展 所以是+lowbit(i)
sum原理:右向左倒退 所以是-lowbit(i)
附上树形图: