Description
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,
分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
Input
第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1
行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
Sample Input
5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
Sample Output
6
9
13
HINT
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5+10;
int head[maxn];
LL value[maxn];
int N,M,edge_cnt;
struct Edge{
int to,next;
}edge[maxn<<1];
void ADD(int u,int v){
edge[edge_cnt].to = v;
edge[edge_cnt].next = head[u];
head[u] = edge_cnt++;
}
int size[maxn],son[maxn],fa[maxn],deep[maxn];
void dfs1(int now,int father,int Deep){
size[now] = 1;
fa[now] = father;
deep[now] = Deep;
son[now] = 0;
for(int i = head[now]; ~i; i = edge[i].next){
int v = edge[i].to;
if(v != father){
dfs1(v,now,Deep+1);
size[now] += size[v];
if(size[son[now]] < size[v])
son[now] = v;
}
}
}
int id[maxn],Rank[maxn],top[maxn],tot,in[maxn],out[maxn];
void dfs2(int now,int Top){
top[now] = Top;
id[now] = ++tot;
in[now] = tot;
Rank[id[now]] = now;
if(son[now])
dfs2(son[now],Top);
for(int i = head[now]; ~i; i = edge[i].next){
int v = edge[i].to;
if(v!=fa[now] && v!=son[now]){
dfs2(v,v);
}
}
out[now] = tot;
}
struct node{
LL sum,lazy;
int l,r;
};
struct SGT{
node tree[maxn<<2];
void pushUp(int now){
tree[now].sum = tree[now<<1].sum+tree[now<<1|1].sum;
}
void pushDown(int now){
tree[now<<1].sum += (LL)(tree[now<<1].r-tree[now<<1].l+1)*tree[now].lazy;
tree[now<<1|1].sum += (LL)(tree[now<<1|1].r-tree[now<<1|1].l+1)*tree[now].lazy;
tree[now<<1].lazy += tree[now].lazy;
tree[now<<1|1].lazy += tree[now].lazy;
tree[now].lazy = 0;
}
void build(int now,int l,int r){
tree[now].lazy = 0;
tree[now].l = l;
tree[now].r = r;
if(l == r){
tree[now].sum = value[Rank[l]];
return;
}
int Mid = (l+r)>>1;
build(now<<1,l,Mid);
build(now<<1|1,Mid+1,r);
pushUp(now);
}
void update(int now,int l,int r,LL val){
if(l <= tree[now].l && tree[now].r <= r){
tree[now].sum += (tree[now].r-tree[now].l+1)*val;
tree[now].lazy += val;
return;
}
pushDown(now);
int Mid = (tree[now].l+tree[now].r)>>1;
if(l <= Mid)
update(now<<1,l,r,val);
if(Mid < r)
update(now<<1|1,l,r,val);
pushUp(now);
}
LL query(int now,int l,int r){
if(l <= tree[now].l && tree[now].r <= r){
return tree[now].sum;
}
LL ans = 0;
pushDown(now);
int Mid = (tree[now].l+tree[now].r)>>1;
if(l <= Mid)
ans += query(now<<1,l,r);
if(Mid < r)
ans += query(now<<1|1,l,r);
pushUp(now);
return ans;
}
};
SGT sgt;
void work(int u){
int tpu = top[u];
LL ans = 0;
while(tpu != 1){
ans += sgt.query(1,id[top[u]],id[u]);
u = fa[tpu];
tpu = top[u];
}
ans += sgt.query(1,1 ,id[u]);
printf("%lld\n",ans);
}
int main(){
while(~scanf("%d %d",&N,&M)){
memset(head,-1,sizeof(head));
edge_cnt = tot = 0;
for(int i = 1; i <= N; i++)
scanf("%lld",&value[i]);
int u,v;
for(int i = 1; i < N; i++){
scanf("%d %d",&u,&v);
ADD(u,v);
ADD(v,u);
}
dfs1(1,0,0);
dfs2(1,1);
sgt.build(1,1,N);
int op,x;
LL val;
while(M--){
scanf("%d %d",&op,&x);
if(op == 1){
scanf("%lld",&val);
sgt.update(1,id[x],id[x],val);
}
else if(op == 2){
scanf("%lld",&val);
sgt.update(1,in[x],out[x],val);
}
else
work(x);
}
}
return 0;
}