• P3178 [HAOI2015]树上操作


    操作 1 :把某个节点 x 的点权增加 a 。
    操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
    操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

    树剖板子

    const int N=1e5+79;
    int a[N],b[N];
    int n,m;
    
    struct graph{
    	int head[N],tot,next[N<<1],ver[N<<1];
    	inline void add(int a,int b){
    		ver[++tot]=b;
    		next[tot]=head[a];
    		head[a]=tot;
    	}
    }G;
    int top[N],dep[N],fa[N],son[N],siz[N],dfn[N],tim;
    inline void dfs1(int x){
    	siz[x]=1;
    	dep[x]=dep[fa[x]]+1;
    	repg(x){
    		int y(G.ver[i]);
    		if(y==fa[x]) continue;
    		fa[y]=x;
    		dfs1(y);
    		siz[x]+=siz[y];
    		if(siz[son[x]]<siz[y]){
    			son[x]=y;
    		}
    	}
    }
    inline void dfs2(int x,int topf){
    	dfn[x]=++tim;
    	b[tim]=a[x];
    	top[x]=topf;
    	if(son[x]){
    		dfs2(son[x],topf);
    	}
    	repg(x){
    		int y(G.ver[i]);
    		if(y==son[x]||y==fa[x]) continue;
    		dfs2(y,y);
    	}
    }
    
    struct SegmentTree{
    	int lc[N<<2],rc[N<<2];
    	lxl sum[N<<2],tag[N<<2];
    	int cnt,rt;
    	inline void pushup(int p){
    		sum[p]=sum[lc[p]]+sum[rc[p]];
    	}
    	inline void pushdown(int &p,int L,int R){
    		if(!tag[p]) return ;
    		int mid(L+R>>1);
    		if(lc[p]){
    			sum[lc[p]]+=(mid-L+1)*tag[p];
    			tag[lc[p]]+=tag[p];
    		}
    		if(rc[p]){
    			sum[rc[p]]+=(R-mid)*tag[p];
    			tag[rc[p]]+=tag[p];
    		}
    		tag[p]=0;
    	}
    	inline void build(int &p,int L,int R){
    		if(!p) p=++cnt;
    		if(L==R){
    			sum[p]=b[L];
    			return ;
    		}
    		int mid(L+R>>1);
    		build(lc[p],L,mid);
    		build(rc[p],mid+1,R);
    		pushup(p);
    	}
    	inline void change(int &p,int L,int R,int ll,int rr,lxl val){
    		if(!p) p=++cnt;
    		if(ll<=L&&rr>=R){
    			sum[p]+=(R-L+1)*val;
    			tag[p]+=val;
    			return;
    		}
    		pushdown(p,L,R);
    		int mid(L+R>>1);
    		if(ll<=mid) change(lc[p],L,mid,ll,rr,val);
    		if(rr>mid) change(rc[p],mid+1,R,ll,rr,val);
    		pushup(p);
    	}inline lxl query(int &p,int L,int R,int ll,int rr){
    		if(!p) return 0;
    		
    		if(ll<=L&&rr>=R){
    			return sum[p];
    		}
    		pushdown(p,L,R);
    		int mid(L+R>>1);
    		lxl ans(0);
    		if(ll<=mid) ans+=query(lc[p],L,mid,ll,rr);
    		if(rr>mid) ans+=query(rc[p],mid+1,R,ll,rr);
    		return ans;
    	}
    }S;
    inline lxl Qchain(int x,int y){
    	lxl ans(0);
    	while(top[x]^top[y]){
    		if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
    		ans+=S.query(S.rt,1,n,dfn[top[x]],dfn[x]);
    		x=fa[top[x]];
    	}
    	if(dep[x]>dep[y]) std::swap(x,y);
    	ans+=S.query(S.rt,1,n,dfn[x],dfn[y]);
    	return ans;
    }
    /*
    5 1
    1 2 3 4 5
    1 2
    1 4
    2 3
    2 5
    3 3
    */
    int main(){
    	read(n);read(m);
    	rep(i,1,n){
    		read(a[i]);
    	}
    	int a,y;
        rep(i,2,n){
        	read(a);read(y);
        	G.add(a,y);
        	G.add(y,a);
    	}
    	
    	dfs1(1);
    	
    	dfs2(1,1);
    	S.build(S.rt,1,n);
    	
    	
    	int op,x;
    	rep(i,1,m){
    		read(op);
    		if(op==1){
    			read(x);read(a);
    			S.change(S.rt,1,n,dfn[x],dfn[x],a);
    		}else if(op==2){
    				read(x);read(a);
    			S.change(S.rt,1,n,dfn[x],dfn[x]+siz[x]-1,a);
    		}else {
    			read(x);
    			out(Qchain(1,x),'\n');
    		}
    	}
    	return 0;
    }
    

    本文来自博客园,作者:{2519},转载请注明原文链接:https://www.cnblogs.com/QQ2519/p/15570774.html

  • 相关阅读:
    Cat- Linux必学的60个命令
    Cmp- Linux必学的60个命令
    Diff- Linux必学的60个命令
    ls- Linux必学的60个命令
    mv- Linux必学的60个命令
    Find- Linux必学的60个命令
    libvirt
    PHP 设计模式 笔记与总结(2)开发 PSR-0 的基础框架
    Java实现 LeetCode 147 对链表进行插入排序
    Java实现 LeetCode 146 LRU缓存机制
  • 原文地址:https://www.cnblogs.com/QQ2519/p/15570774.html
Copyright © 2020-2023  润新知