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
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
预处理树的前序和后序遍历的编号
按编号用两棵线段树分别维护区间和
子树的编号连续可以直接修改
结点到根的路径和可以用前序和后序的信息相减得到
时间复杂度O(nlogn)
#include<cstdio> #include<cstring> #define N 100005 typedef long long lint; int n,m,a,b,o; int v[N]; int es[N*3],enx[N*3],ep=N; void addedge(int a,int b){ es[ep]=b; enx[ep]=enx[a]; enx[a]=ep++; es[ep]=a; enx[ep]=enx[b]; enx[b]=ep++; } struct sgt{ lint s[262144]; lint a[262144]; sgt(){ memset(s,0,sizeof(s)); memset(a,0,sizeof(a)); } void down(int w,int l,int r){ if(l<r){ a[w+w]+=a[w]; a[w+w+1]+=a[w]; int x=(r+1-l)>>1; s[w+w]+=a[w]*x; s[w+w+1]+=a[w]*x; } a[w]=0; } void add(int l,int r,lint x,int w=1,int L=1,int R=131072){ int M=L+R>>1; if(a[w])down(w,L,R); if(l==L&&r==R){ a[w]+=x; s[w]+=x*(R+1-L); return; } if(r<=M)add(l,r,x,w+w,L,M); else if(l>M)add(l,r,x,w+w+1,M+1,R); else add(l,M,x,w+w,L,M),add(M+1,r,x,w+w+1,M+1,R); s[w]=s[w+w]+s[w+w+1]; } lint get(int l,int r,int w=1,int L=1,int R=131072){ int M=L+R>>1; if(a[w])down(w,L,R); if(l==L&&r==R)return s[w]; if(r<=M)return get(l,r,w+w,L,M); else if(l>M)return get(l,r,w+w+1,M+1,R); else return get(l,M,w+w,L,M)+get(M+1,r,w+w+1,M+1,R); } }t1,t2; int i1[N],i2[N],m1[N],m2[N],p1=1,p2=2; void f(int w,int pa){ i1[w]=p1++; m2[w]=p2; for(int i=enx[w];i;i=enx[i]){ int u=es[i]; if(u!=pa)f(u,w); } m1[w]=p1-1; i2[w]=p2++; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",v+i); for(int i=1;i<n;i++){ scanf("%d%d",&a,&b); addedge(a,b); } f(1,0); for(int i=1;i<=n;i++){ t1.add(i1[i],i1[i],v[i]); t2.add(i2[i],i2[i],v[i]); } while(m--){ scanf("%d",&o); if(o==1){ scanf("%d%d",&a,&b); t1.add(i1[a],i1[a],b); t2.add(i2[a],i2[a],b); }else if(o==2){ scanf("%d%d",&a,&b); t1.add(i1[a],m1[a],b); t2.add(m2[a],i2[a],b); }else{ scanf("%d",&a); printf("%lld\n",t1.get(1,i1[a])-t2.get(1,m2[a]-1)); } } return 0; }