• [HAOI2015]树上操作


    题目:BZOJ4034、洛谷P3178。

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

    操作 1 :把某个节点 x 的点权增加 a 。
    操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
    操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
    现在要你输出所有询问的答案。
    解题思路:对树上的节点修改查询,很容易想到树链剖分。
    单点修改就相当于只包含一个节点的区间修改。
    子树修改,由于树链剖分中一棵子树的dfs序连续,相当于区间修改。
    查询就相当于多次区间查询。
    树链剖分时间复杂度$O(nlog^2 n)$。
    C++ Code:
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #define N 100005
    #define mem(a) memset(&a,0,sizeof a)
    #define ll long long
    int n,m,a[N],aa[N],dfn[N],idx,cnt,head[N],sz[N],fa[N],top[N],son[N],dep[N];
    ll ans;
    struct edge{
    	int to,nxt;
    }e[N<<1];
    struct SegmentTreeNode{
    	ll s,add;
    }d[N<<2];
    inline int readint(){
    	char c=getchar();
    	bool b=false;
    	for(;!isdigit(c);c=getchar())b=c=='-';
    	int d=0;
    	for(;isdigit(c);c=getchar())
    	d=(d<<3)+(d<<1)+(c^'0');
    	return b?-d:d;
    }
    void dfs(int now){
    	sz[now]=1;
    	for(int i=head[now];i;i=e[i].nxt)
    	if(!dep[e[i].to]){
    		dep[e[i].to]=dep[now]+1;
    		fa[e[i].to]=now;
    		dfs(e[i].to);
    		sz[now]+=sz[e[i].to];
    		if(!son[now]||sz[e[i].to]>sz[son[now]])
    		son[now]=e[i].to;
    	}
    }
    void dfs2(int now){
    	dfn[now]=++idx;
    	if(son[now])top[son[now]]=top[now],dfs2(son[now]);
    	for(int i=head[now];i;i=e[i].nxt)
    	if(dep[e[i].to]>dep[now]&&e[i].to!=son[now])
    	top[e[i].to]=e[i].to,dfs2(e[i].to);
    }
    inline void pushdown(int len,int o){
    	int l=o<<1,r=o<<1|1;
    	d[l].add+=d[o].add;
    	d[r].add+=d[o].add;
    	d[l].s+=d[o].add*((len+1)>>1);
    	d[r].s+=d[o].add*(len>>1);
    	d[o].add=0;
    }
    void build(int l,int r,int o){
    	if(l==r){
    		d[o].s=aa[l];
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(l,mid,o<<1);
    	build(mid+1,r,o<<1|1);
    	d[o].s=d[o<<1].s+d[o<<1|1].s;
    }
    void add(int l,int r,int o,int L,int R,int k){
    	if(L<=l&&r<=R){
    		d[o].add+=k;
    		d[o].s+=(ll)k*(r-l+1);
    		return;
    	}
    	pushdown(r-l+1,o);
    	int mid=(l+r)>>1;
    	if(L<=mid)add(l,mid,o<<1,L,R,k);
    	if(mid<R)add(mid+1,r,o<<1|1,L,R,k);
    	d[o].s=d[o<<1].s+d[o<<1|1].s;
    }
    void query(int l,int r,int o,int L,int R){
    	if(L<=l&&r<=R){
    		ans+=d[o].s;
    		return;
    	}
    	pushdown(r-l+1,o);
    	int mid=(l+r)>>1;
    	if(L<=mid)query(l,mid,o<<1,L,R);
    	if(mid<R)query(mid+1,r,o<<1|1,L,R);
    }
    void que(int x){
    	while(top[x]!=1){
    		query(1,n,1,dfn[top[x]],dfn[x]);
    		x=fa[top[x]];
    	}
    	query(1,n,1,dfn[1],dfn[x]);
    }
    int main(){
    	idx=cnt=0;
    	n=readint(),m=readint();
    	mem(dfn);mem(head);mem(sz);mem(fa);mem(top);mem(son);mem(dep);mem(d);
    	for(int i=1;i<=n;++i)a[i]=readint();
    	for(int i=1;i<n;++i){
    		int u=readint(),v=readint();
    		e[++cnt]=(edge){v,head[u]};
    		head[u]=cnt;
    		e[++cnt]=(edge){u,head[v]};
    		head[v]=cnt;
    	}
    	fa[1]=top[1]=dep[1]=1;
    	dfs(1);dfs2(1);
    	for(int i=1;i<=n;++i)aa[dfn[i]]=a[i];
    	build(1,n,1);
    	while(m--){
    		int f=readint();
    		if(f==1){
    			int x=readint(),k=readint();
    			add(1,n,1,dfn[x],dfn[x],k);
    		}else
    		if(f==2){
    			int x=readint(),k=readint();
    			add(1,n,1,dfn[x],dfn[x]+sz[x]-1,k);
    		}else{
    			int x=readint();
    			ans=0;
    			que(x);
    			printf("%lld
    ",ans);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    字符串系列复习
    点分治总结
    LCT总结
    网络流总结
    centOS7下安装GUI图形界面
    周记 2014.10.8
    周记 2014.9.28
    周记 2014.9.20
    tar命令
    [转]bit与byte
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/7786884.html
Copyright © 2020-2023  润新知