这个题多了一个操作难度直线上升,看完题解才会写
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
按照题意:记录其DFS序,然后进栈是正,出栈为负,利用线段树进行更新
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <math.h> #include <vector> #include <stack> using namespace std; typedef long long LL; const int N = 800005; struct Edge { int v,next; } edge[N<<1]; int head[N],tot,cnt; int val[N]; int in[N],out[N]; LL tree[N<<2],lazy[N<<2],seg[N]; int flag[N<<2]; int io[N]; void addEdge(int u,int v) { edge[tot].v = v,edge[tot].next = head[u],head[u] = tot++; } void init() { memset(head,-1,sizeof(head)); memset(val,0,sizeof(val)); memset(lazy,0,sizeof(lazy)); memset(io,0,sizeof(io)); memset(seg,0,sizeof(seg)); tot = cnt = 0; } void dfs(int u,int fa) { seg[in[u] = ++cnt] = (LL)val[u]; io[cnt] = 1; for(int i=head[u]; i!=-1; i=edge[i].next) { if(edge[i].v != fa) { dfs(edge[i].v,u); } } seg[out[u] = ++cnt] = (LL)(-val[u]); io[cnt] = -1; } void pushup(int idx) { tree[idx] = tree[idx<<1]+tree[idx<<1|1]; return; } void pushdown(int idx) { if(lazy[idx]) { tree[idx << 1] += flag[idx<<1]*lazy[idx]; tree[idx << 1 | 1] += flag[idx<<1|1]*lazy[idx]; lazy[idx << 1] += lazy[idx]; lazy[idx << 1 | 1] += lazy[idx]; lazy[idx] = 0; } return; } void build(int l,int r,int idx) { if(l==r) { tree[idx] = seg[l]; if(io[l]>0) flag[idx] = 1; else flag[idx] = -1; return; } int mid = (l+r)>>1; build(l,mid,idx<<1); build(mid+1,r,idx<<1|1); pushup(idx); flag[idx] = flag[idx<<1] + flag[idx<<1|1]; } void update(int l,int r,int L,int R,int idx,int val) { if(l>=L&&r<=R) { tree[idx] =tree[idx] + (LL)flag[idx]*val; lazy[idx] =lazy[idx] + (LL)val; return; } int mid = (l+r)>>1; pushdown(idx); if(mid>=L) update(l,mid,L,R,idx<<1,val); if(mid<R) update(mid+1,r,L,R,idx<<1|1,val); pushup(idx); } LL query(int l,int r,int L,int R,int idx){ if(l>=L&&r<=R) { return tree[idx]; } int mid = (l+r)>>1; LL sum = 0; pushdown(idx); if(mid>=L) sum+=query(l,mid,L,R,idx<<1); if(mid<R) sum+=query(mid+1,r,L,R,idx<<1|1); return sum; } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { init(); 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); addEdge(u,v); addEdge(v,u); } dfs(1,0); build(1,2*n,1); while(m--) { int op,x,y; scanf("%d",&op); if(op==1) { scanf("%d%d",&x,&y); update(1,2*n,in[x],in[x],1,y); update(1,2*n,out[x],out[x],1,y); }else if(op==2){ scanf("%d%d",&x,&y); update(1,2*n,in[x],out[x],1,y); }else{ scanf("%d",&x); LL sum = query(1,2*n,1,in[x],1); printf("%lld ",sum); } } } }