思路:
最朴素的做法:维护一个dp[i]:以i为子树的所有结点和,然后对于每个节点更新,朴素的更新它父亲节点的值,但是,如果树是一个长链这个就超时了。
正解:
先dfs求一个dfs序,这样以i节点的子树都是在一段区间内,所以我们可以维护一下i的子树的数量,那么求以i为根的子树和就是[dfs(i) - 1,dfs(i) + son[i] - 1]区间和,dfs(i):i节点的dfs序。
子树的和用一个区间和就解决了,那么修改节点i的值无非就是单点更新,树状数组维护一下即可。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 2e6 + 10; vector<int>G[maxn]; int tot,cnt[maxn]; int n,m,root; int val[maxn],son[maxn],s[maxn]; void dfs(int u,int fu){ son[u] = 1; cnt[u] = ++tot; for(int i = 0; i < G[u].size(); i++){ int v = G[u][i]; if(v != fu){ dfs(v,u); son[u] += son[v]; } } } void update(int x,int v){ for(; x <= maxn; x += (x & -x)){ s[x] += v; } } int query(int x){ int sum = 0; for(; x ; x -= (x & -x)){ sum += s[x]; } return sum; } void solved(){ scanf("%d%d%d",&n,&m,&root); for(int i = 1; i <= n; i++)scanf("%d",&val[i]); for(int i = 1; i < n; i++){ int u,v;scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } dfs(root,0); for(int i = 1; i <= n; i++)update(cnt[i],val[i]); while(m--){ int ins;scanf("%d",&ins); if(1 == ins){ int a,x;scanf("%d%d",&a,&x); update(cnt[a],x); }else { int a;scanf("%d",&a); printf("%d\n",query(cnt[a] + son[a] - 1) - query(cnt[a] - 1)); } } } int main(){ solved(); return 0; }