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 。
题解:树链剖分裸体,支持点修改,链查询,子树修改,子树查询。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=100100; int point[N],next[N*4],belong[N],siz[N],son[N],pos[N],deep[N]; int n,m,tot=1,num=0,fa[N]; long long tr[N*4],de[N*4],r[N]; bool use[N]; struct S{ int st,en; }aa[N*4]; inline void add(int x,int y) { tot+=1;next[tot]=point[x];point[x]=tot; aa[tot].st=x;aa[tot].en=y; tot+=1;next[tot]=point[y];point[y]=tot; aa[tot].st=y;aa[tot].en=x; } inline void dfs_1(int x) { int i; siz[x]=1; use[x]=false; for(i=point[x];i;i=next[i]) if(use[aa[i].en]){ deep[aa[i].en]=deep[x]+1; fa[aa[i].en]=x; dfs_1(aa[i].en); siz[x]+=siz[aa[i].en]; } } inline void dfs_2(int x,int y) { int i,k=0; num+=1; pos[x]=son[x]=num; belong[x]=y; for(i=point[x];i;i=next[i]) if(deep[x]<deep[aa[i].en]&&siz[k]<siz[aa[i].en]) k=aa[i].en; if(k==0) return ; dfs_2(k,y);son[x]=max(son[k],son[x]); for(i=point[x];i;i=next[i]) if(deep[x]<deep[aa[i].en]&&k!=aa[i].en){ dfs_2(aa[i].en,aa[i].en); son[x]=max(son[x],son[aa[i].en]); } } #define mid (l+r)/2 #define L k<<1,l,mid #define R k<<1|1,mid+1,r inline void paint(int k,int l,int r,long long z) { de[k]+=z; tr[k]+=(r-l+1)*z; } inline void pushdown(int k,int l,int r) { if(l==r) return ; paint(L,de[k]); paint(R,de[k]); de[k]=0; } inline void insert(int k,int l,int r,int x,long long y) { if(l==r&&l==x){ tr[k]+=y; return ; } pushdown(k,l,r); if(x<=mid) insert(L,x,y); else insert(R,x,y); tr[k]=tr[k<<1]+tr[k<<1|1]; } inline void change(int k,int l,int r,int x,int y,long long z) { if(x<=l&&y>=r){ paint(k,l,r,z); return ; } pushdown(k,l,r); if(x<=mid) change(L,x,y,z); if(y>mid) change(R,x,y,z); tr[k]=tr[k<<1]+tr[k<<1|1]; } inline long long qurey(int k,int l,int r,int x,int y) { long long sum=0; if(x<=l&&y>=r) return tr[k]; pushdown(k,l,r); if(x<=mid) sum+=qurey(L,x,y); if(y>mid) sum+=qurey(R,x,y); return sum; } inline long long ask(int x,int y) { long long sum=0; while(belong[x]!=belong[y]){ sum+=qurey(1,1,n,pos[belong[x]],pos[x]); x=fa[belong[x]]; } sum+=qurey(1,1,n,pos[y],pos[x]); return sum; } int main() { int i,j,x,t,root; long long y; memset(use,1,sizeof(use)); scanf("%d%d",&n,&m); for(i=1;i<=n;++i) scanf("%lld",&r[i]); for(i=1;i<n;++i){ scanf("%d%d",&x,&y); add(x,y); } dfs_1(1); dfs_2(1,1); for(i=1;i<=n;++i){ insert(1,1,n,pos[i],r[i]); if(deep[i]==0) root=i; } while(m--){ scanf("%d",&t); if(t==1||t==2){ scanf("%d%lld",&x,&y); if(t==1) insert(1,1,n,pos[x],y); if(t==2) change(1,1,n,pos[x],son[x],y); } else{ scanf("%d",&x); printf("%lld\n",ask(x,root)); } } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-11-19 14:56:00