• 树链剖分【洛谷P3833】 [SHOI2012]魔法树


    P3833 [SHOI2012]魔法树

    题目描述

    Harry Potter 新学了一种魔法:可以让改变树上的果子个数。满心欢喜的他找到了一个巨大的果树,来试验他的新法术。

    这棵果树共有N个节点,其中节点0是根节点,每个节点u的父亲记为fa[u],保证有fa[u] < u。初始时,这棵果树上的果子都被 Dumbledore 用魔法清除掉了,所以这个果树的每个节点上都没有果子(即0个果子)。

    不幸的是,Harry 的法术学得不到位,只能对树上一段路径的节点上的果子个数统一增加一定的数量。也就是说,Harry 的魔法可以这样描述:

    Add u v d

    表示将点u和v之间的路径上的所有节点的果子个数都加上d。

    接下来,为了方便检验 Harry 的魔法是否成功,你需要告诉他在释放魔法的过程中的一些有关果树的信息:

    Query u

    表示当前果树中,以点u为根的子树中,总共有多少个果子?

    输入输出格式

    输入格式:

    第一行一个正整数N (1 ≤ N ≤ 100000),表示果树的节点总数,节点以0,1,…,N − 1标号,0一定代表根节点。

    接下来N − 1行,每行两个整数a,b (0 ≤ a < b < N),表示a是b的父亲。

    接下来是一个正整数Q(1 ≤ Q ≤ 100000),表示共有Q次操作。

    后面跟着Q行,每行是以下两种中的一种:

    1. A u v d,表示将u到v的路径上的所有节点的果子数加上d;0 ≤ u,v <N,0 < d < 100000
    2. Q u,表示询问以u为根的子树中的总果子数,注意是包括u本身的。

    输出格式:

    对于所有的Query操作,依次输出询问的答案,每行一个。答案可能会超过2^32 ,但不会超过10^15 。

    省选考树剖裸题。。。

    code:

    #include <iostream>
    #include <cstdio>
    #define ls(o) o<<1
    #define rs(o) o<<1|1
    #define int long long
    
    using namespace std;
    const int wx=100017;
    
    inline int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    int dfn[wx],tid[wx];
    int dep[wx],f[wx],size[wx],son[wx];
    int top[wx];
    int head[wx],a[wx];
    int n,m,num,tot;
    char opt[17];
    
    struct val_tree{
    	int l,r,tag,sum;
    	#define tag(o) t[o].tag
    	#define sum(o) t[o].sum
    }t[wx*4];
    void up(int o){
    	sum(o)=sum(ls(o))+sum(rs(o));
    }
    void down(int o){
    	if(tag(o)){
    		sum(ls(o))+=tag(o)*(t[ls(o)].r-t[ls(o)].l+1);
    		sum(rs(o))+=tag(o)*(t[rs(o)].r-t[rs(o)].l+1);
    		tag(ls(o))+=tag(o); tag(rs(o))+=tag(o);
    		tag(o)=0;
    	}
    }
    void build(int o,int l,int r){
    	t[o].l=l;t[o].r=r;
    	if(l==r){sum(o)=a[tid[l]];return ;}
    	int mid=t[o].l+t[o].r>>1;
    	if(l<=mid)build(ls(o),l,mid);
    	if(r>mid)build(rs(o),mid+1,r);
    	up(o);
    }
    void update_t(int o,int l,int r,int k){
    	if(l<=t[o].l&&t[o].r<=r){
    		sum(o)+=k*(t[o].r-t[o].l+1);
    		tag(o)+=k; return ;
    	}
    	down(o);
    	int mid=t[o].l+t[o].r>>1;
    	if(l<=mid)update_t(ls(o),l,r,k);
    	if(r>mid)update_t(rs(o),l,r,k);
    	up(o);
    }
    int query_t(int o,int l,int r){
    	if(l<=t[o].l&&t[o].r<=r){
    		return sum(o);
    	}
    	down(o); int sum=0;
    	int mid=t[o].l+t[o].r>>1;
    	if(l<=mid)sum+=query_t(ls(o),l,r);
    	if(r>mid)sum+=query_t(rs(o),l,r);
    	return sum;
    }
    //~~~~~~~~~~~~~~~~~~~~~~~~
    struct e{
    	int nxt,to;
    }edge[wx*2];
    void add(int from,int to){
    	edge[++num].nxt=head[from];
    	edge[num].to=to;
    	head[from]=num;
    }
    void first_dfs(int u,int fa){
    	f[u]=fa;dep[u]=dep[fa]+1;
    	size[u]=1;
    	int maxson=-1;
    	for(int i=head[u];i;i=edge[i].nxt){
    		int v=edge[i].to;
    		if(v==fa)continue;
    		first_dfs(v,u);
    		size[u]+=size[v];
    		if(size[v]>maxson){
    			son[u]=v; maxson=size[v];
    		}
    	}
    }
    void second_dfs(int u,int topf){
    	dfn[u]=++tot;
    	top[u]=topf;
    	tid[tot]=u;
    	if(son[u]){
    		second_dfs(son[u],topf);
    	}
    	for(int i=head[u];i;i=edge[i].nxt){
    		int v=edge[i].to;
    		if(dfn[v]||v==son[u])continue;
    		second_dfs(v,v);
    	}
    }
    void update(int x,int y,int k){
    	int fx=top[x]; int fy=top[y];
    	while(fx!=fy){
    		if(dep[fx]>dep[fy]){
    			update_t(1,dfn[fx],dfn[x],k);
    			x=f[fx];
    		}
    		else{
    			update_t(1,dfn[fy],dfn[y],k);
    			y=f[fy];
    		}
    		fx=top[x]; fy=top[y];
    	}
    	if(dfn[x]>dfn[y]) swap(x,y);
    	update_t(1,dfn[x],dfn[y],k);
    	return ;
    }
    signed main(){
    	n=read();
    	for(int i=1;i<n;i++){
    		int x,y;
    		x=read(); y=read();
    		x++; y++;
    		add(x,y);add(y,x);
    	}
    	first_dfs(1,0);
    	second_dfs(1,1);
    	build(1,1,n);
    	m=read();
    	for(int i=1;i<=m;i++){
    		scanf("%s",opt+1);
    		if(opt[1]=='A'){
    			int x,y,z;
    			x=read();y=read();z=read();
    			x++; y++;
    			update(x,y,z);
    		}
    		else{
    			int x; x=read(); x++;
    			printf("%lld
    ",query_t(1,dfn[x],dfn[x]+size[x]-1));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    cocospods 卡在 Analyzing dependencies
    android px、sp、dp之间的互转
    Android 4.4环境搭建——Android SDK下载与安装
    我心中的核心组件(可插拔的AOP)~大话开篇及目录
    EF架构~AutoMapper对象映射工具简化了实体赋值的过程
    我心中的核心组件(可插拔的AOP)~第二回 缓存拦截器
    EF架构~为EF DbContext生成的实体添加注释(T5模板应用)
    品味编程~底层开发人员应该这样设计一个字体类
    Study notes for Clustering and K-means
    深入理解Oracle索引(25):一招鲜、吃遍天之单字段索引创建思路
  • 原文地址:https://www.cnblogs.com/wangxiaodai/p/9790916.html
Copyright © 2020-2023  润新知