[HAOI2015]树上操作
题目描述
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a 。操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
输入输出格式
输入格式:
第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 行每行两个正整数 from, to , 表示该树中存在一条边 (from, to) 。再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
输出格式:
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
输入输出样例
说明
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不
会超过 10^6 。
比洛谷板子还简单。。。不解释了,应该都会吧
#include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<iostream> #define ll long long using namespace std; struct node{ ll to,next; }e[500001]; ll head[500001],dep[500001],sum[500001],a[500001]; ll tot,num,n,m,lazy[500001],fa[500001],l[500001]; ll ch[500001],top[500001],size[500001],son[500001]; void build(int root,int l,int r) { if(l==r){sum[root]=a[l];return ;} int mid=(l+r)>>1; build(root<<1,l,mid); build(root<<1|1,mid+1,r); sum[root]=sum[root<<1]+sum[root<<1|1]; return ; } void push(int root,int l,int r) { int mid=(l+r)>>1; lazy[root<<1]+=lazy[root]; lazy[root<<1|1]+=lazy[root]; sum[root<<1]+=lazy[root]*(mid-l+1); sum[root<<1|1]+=lazy[root]*(r-mid); lazy[root]=0; return ; } void update(int root,int left,int right,int l,int r,ll k) { if(l<=left&&r>=right) { sum[root]+=k*(right-left+1); lazy[root]+=k; return; } if(left>r||right<l)return ; int mid=(left+right)>>1; if(lazy[root])push(root,left,right); if(mid>=l)update(root<<1,left,mid,l,r,k); if(mid<r) update(root<<1|1,mid+1,right,l,r,k); sum[root]=sum[root<<1|1]+sum[root<<1]; return; } ll query(int root,int left,int right,int l,int r) { if(l<=left&&r>=right)return sum[root]; if(left>r||right<l)return 0; int mid=(left+right)>>1; if(lazy[root])push(root,left,right); ll a=0,b=0; if(mid>=l) a=query(root<<1,left,mid,l,r); if(mid<r) b=query(root<<1|1,mid+1,right,l,r); return a+b; } void dfs1(int x) { size[x]=1; for(int i=head[x];i;i=e[i].next) { int v=e[i].to; if(!dep[v]) { dep[v]=dep[x]+1; fa[v]=x; dfs1(v); size[x]+=size[v]; if(size[v]>size[son[x]])son[x]=v; } } return ; } void dfs2(int x,int t) { l[x]=++tot;a[tot]=ch[x];top[x]=t; if(son[x])dfs2(son[x],t); for(int i=head[x];i;i=e[i].next) { int v=e[i].to; if(v!=fa[x]&&v!=son[x]) dfs2(v,v); } return ; } ll cal(int x,int y) { ll maxx=0; int fx=top[x],fy=top[y]; while(fx!=fy) { if(dep[fx]<dep[fy]) { swap(x,y);swap(fx,fy); } maxx+=query(1,1,tot,l[fx],l[x]); x=fa[fx]; fx=top[x]; } if(l[x]>l[y])swap(x,y); maxx+=query(1,1,tot,l[x],l[y]); return maxx; } ll read() { ll x=0,w=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*w; } void add(int from,int to) { num++; e[num].to=to; e[num].next=head[from]; head[from]=num; } int main() { n=read();m=read(); for(int i=1;i<=n;i++) { ch[i]=read(); } for(int i=1;i<n;i++) { int x,y; x=read();y=read(); add(x,y);add(y,x); } dep[1]=1; fa[1]=1; dfs1(1); dfs2(1,1); build(1,1,n); for(int i=1;i<=m;i++) { int qwq; qwq=read(); if(qwq==1) { ll x,y; x=read();y=read(); update(1,1,tot,l[x],l[x],y); } if(qwq==2) { ll x,y; x=read();y=read(); update(1,1,tot,l[x],l[x]+size[x]-1,y); } if(qwq==3) { int x; x=read(); printf("%lld\n",cal(x,1)); } } return 0; }