[HAOI2015]树上操作

洛咕

题意:有一棵点数为N的树,以点1为根,且树点有边权.然后有M个操作,分为三种:

操作1:把某个节点x的点权增加a.

操作2:把某个节点x为根的子树中所有点的点权都增加a.

操作3:询问某个节点x到根的路径中所有点的点权和.

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
int n,m,val[100005];
long long ans,add[400005],sum[400005];
int size[100005],deep[100005],fa[100005],son[100005];
int rev[400005],seg[100005],top[100005];
int tot,head[100005],nxt[200005],to[200005];
void add_edge(int a,int b){
    nxt[++tot]=head[a];head[a]=tot;to[tot]=b;
    nxt[++tot]=head[b];head[b]=tot;to[tot]=a;
}
void dfs1(int u){
    size[u]=1;
    for(int i=head[u];i;i=nxt[i]){
		int v=to[i];
		if(v==fa[u])continue;
		deep[v]=deep[u]+1;fa[v]=u;
		dfs1(v);
		size[u]+=size[v];
		if(size[son[u]]<size[v])son[u]=v;
    }
}
void dfs2(int u){
    if(son[u]){
		top[son[u]]=top[u];
		seg[son[u]]=++seg[0];
		rev[seg[0]]=son[u];
		dfs2(son[u]);
    }
    for(int i=head[u];i;i=nxt[i]){
		int v=to[i];
		if(!top[v]){
	    	top[v]=v;
	    	seg[v]=++seg[0];
	    	rev[seg[0]]=v; 
	    	dfs2(v);
		}
    }
}
void build(int k,int l,int r){
    if(l==r){sum[k]+=val[rev[l]];return;}
    int mid=(l+r)>>1;
    build(k<<1,l,mid);build((k<<1)|1,mid+1,r);
    sum[k]=sum[k<<1]+sum[(k<<1)|1];
    return;
}
void Add(int k,int l,int r,int val){
    add[k]+=val;
    sum[k]+=(r-l+1)*val;
    return;
}
void pushdown(int k,int l,int r,int mid){
    if(add[k]==0)return;
    Add(k<<1,l,mid,add[k]);Add((k<<1)|1,mid+1,r,add[k]);
    add[k]=0;
}
void change1(int k,int l,int r,int L,int R,int val){
    if(r<L||R<l)return;
    if(L<=l&&r<=R){sum[k]+=val*(r-l+1);add[k]+=val;return;}
    int mid=(l+r)>>1;
    pushdown(k,l,r,mid);
    change1(k<<1,l,mid,L,R,val);
    change1((k<<1)|1,mid+1,r,L,R,val);
    sum[k]=sum[k<<1]+sum[(k<<1)|1];
}
void change2(int k,int l,int r,int L,int R,int val){
    if(L<=l&&r<=R)return Add(k,l,r,val);
    int mid=(l+r)>>1;
    pushdown(k,l,r,mid);
    if(L<=mid)change2(k<<1,l,mid,L,R,val);
    if(R>mid)change2((k<<1)|1,mid+1,r,L,R,val);
    sum[k]=sum[k<<1]+sum[(k<<1)|1];
}
int query(int k,int l,int r,int L,int R){
    if(l>=L&&r<=R)return sum[k];
    int mid=(l+r)>>1;
    pushdown(k,l,r,mid);
    long long res=0;
    if(L<=mid)res=(res+query(k<<1,l,mid,L,R));
    if(R>mid)res=(res+query((k<<1)|1,mid+1,r,L,R));
    return res;
}
void ask(int x,int y){
    long long ans=0;
    while(top[x]!=top[y]){
		if(deep[top[x]]<deep[top[y]])swap(x,y);
		ans+=query(1,1,seg[0],seg[top[x]],seg[x]);
		x=fa[top[x]];
    }
    if(deep[x]>deep[y])swap(x,y);
    ans+=query(1,1,seg[0],seg[x],seg[y]);
    printf("%lld
",ans);
}
signed main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)val[i]=read();
    for(int i=1;i<n;i++)add_edge(read(),read());
    rev[1]=seg[0]=seg[1]=top[1]=deep[1]=1;
    dfs1(1);dfs2(1);build(1,1,seg[0]);
    int opt,x,y;
    while(m--){
		opt=read();
		if(opt==1){x=read();y=read();change1(1,1,seg[0],seg[x],seg[x],y);continue;}
		if(opt==2){x=read();y=read();change2(1,1,seg[0],seg[x],seg[x]+size[x]-1,y);continue;}
		if(opt==3){x=read();ask(1,x);continue;}
    }
    return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/10561705.html