zoukankan      html  css  js  c++  java
  • BZOJ4034 [HAOI2015]树上操作 树链剖分

    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ4034


    题意概括

    有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个

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

    题解

      树链剖分。

      然后对于子树修改,我们可以考虑dfs序

      树链剖分也是一种dfs序。

      单点修改更简单,对于懒惰的我来说,这就是区间修改(少写了一个void 2333)

      询问几乎是基础的树剖了,沿着树链往上走就可以了。


    代码

    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstdlib>
    using namespace std;
    typedef long long LL;
    const int N=100005;
    struct Gragh{
    	int cnt,y[N*2],nxt[N*2],fst[N];
    	void clear(){
    		cnt=0;
    		memset(fst,0,sizeof fst);
    	}
    	void add(int a,int b){
    		y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
    	}
    }g;
    int n,m,cnp=0;
    int fa[N],son[N],size[N],depth[N],top[N],p[N],ap[N],outp[N];
    LL v[N],t[N*4],add[N*4],w[N*4];
    void Get_Gen_Info(int rt,int pre,int d){
    	size[rt]=1,fa[rt]=pre,depth[rt]=d,son[rt]=-1;
    	for (int i=g.fst[rt];i;i=g.nxt[i])
    		if (g.y[i]!=pre){
    			int s=g.y[i];
    			Get_Gen_Info(s,rt,d+1);
    			size[rt]+=size[s];
    			if (son[rt]==-1||size[s]>size[son[rt]])
    				son[rt]=s;
    		}
    }
    void Get_Top(int rt,int tp){
    	top[rt]=tp;
    	ap[p[rt]=++cnp]=rt;
    	if (son[rt]==-1){
    		outp[rt]=cnp;
    		return;
    	}
    	Get_Top(son[rt],tp);
    	for (int i=g.fst[rt];i;i=g.nxt[i]){
    		int s=g.y[i];
    		if (s!=fa[rt]&&s!=son[rt])
    			Get_Top(s,s);
    	}
    	outp[rt]=cnp;
    }
    void pushup(int rt){
    	int ls=rt<<1,rs=ls|1;
    	t[rt]=t[ls]+t[rs];
    }
    void build(int rt,int le,int ri){
    	w[rt]=ri-le+1;
    	add[rt]=0;
    	if (le==ri){
    		t[rt]=v[ap[le]];
    		return;
    	}
    	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
    	build(ls,le,mid);
    	build(rs,mid+1,ri);
    	pushup(rt);
    }
    void pushdown(int rt){
    	int ls=rt<<1,rs=ls|1;
    	LL &a=add[rt];
    	if (a){
    		t[ls]+=w[ls]*a,add[ls]+=a;
    		t[rs]+=w[rs]*a,add[rs]+=a;
    		a=0;
    	}
    }
    void update(int rt,int le,int ri,int xle,int xri,LL d){
    	if (le>xri||ri<xle)
    		return;
    	if (xle<=le&&ri<=xri){
    		t[rt]+=w[rt]*d,add[rt]+=d;
    		return;
    	}
    	pushdown(rt);
    	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
    	update(ls,le,mid,xle,xri,d);
    	update(rs,mid+1,ri,xle,xri,d);
    	pushup(rt);
    }
    LL query(int rt,int le,int ri,int xle,int xri){
    	if (le>xri||ri<xle)
    		return 0;
    	if (xle<=le&&ri<=xri)
    		return t[rt];
    	pushdown(rt);
    	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
    	return query(ls,le,mid,xle,xri)+query(rs,mid+1,ri,xle,xri);
    }
    LL Tquery(int a){
    	int f=top[a];
    	LL ans=0;
    	while (a){
    		ans+=query(1,1,n,p[f],p[a]);
    		a=fa[f],f=top[a];
    	}
    	return ans;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    		scanf("%lld",&v[i]);
    	g.clear();
    	for (int i=1,a,b;i<n;i++){
    		scanf("%d%d",&a,&b);
    		g.add(a,b);
    		g.add(b,a);
    	}
    	Get_Gen_Info(1,0,0);
    	Get_Top(1,1);
    	build(1,1,n);
    	for (int i=1;i<=m;i++){
    		int op,a,b;
    		scanf("%d",&op);
    		if (op==1){
    			scanf("%d%d",&a,&b);
    			update(1,1,n,p[a],p[a],b);
    		}
    		if (op==2){
    			scanf("%d%d",&a,&b);
    			update(1,1,n,p[a],outp[a],b);
    		}
    		if (op==3){
    			scanf("%d",&a);
    			printf("%lld
    ",Tquery(a));
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    java中a++和++a的区别详解
    Oracle 对比两张表不一样 的数据
    通配符的匹配很全面, 但无法找到元素 'tx:annotation-driven' 的声明
    Java语言基础-运算符
    java中+=详解 a+=b和a=a+b的区别
    java语言基础-变量
    java语言基础-进制
    Spring整合CXF发布及调用WebService
    Oracle Job定时任务的使用详解
    MySQL的主从配置
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ4034.html
Copyright © 2011-2022 走看看