zoukankan      html  css  js  c++  java
  • P3833 [SHOI2012]魔法树

    题目背景

    SHOI2012 D2T3

    题目描述

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

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

    不幸的是,Harry 的法术学得不到位,只能对树上一段路径的节点上的果子个数统一增加一定的数量。也就是说,Harry 的魔法可以这样描述:A u v d 。表示将点 u和 v 之间的路径上的所有节点的果子个数都加上 d**。

    接下来,为了方便检验 Harry 的魔法是否成功,你需要告诉他在释放魔法的过程中的一些有关果树的信息:Q u。表示当前果树中,以点 uu 为根的子树中,总共有多少个果子?

    输入格式

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

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

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

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

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

    输出格式

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

    输入输出样例

    输入 #1复制

    4
    0 1
    1 2
    2 3
    4
    A 1 3 1
    Q 0
    Q 1
    Q 2
    

    输出 #1复制

    3
    3
    2
    

    思路

    支持两个操作,链上修改,子树查询

    树剖裸题,代码就在板子基础上,改改输入输出就行

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=200100;
    typedef long long LL;
    const int M=N*2;
    int n,m;
    int head[N],ver[N],ne[N],idx;
    int w[N];
    int id[N],nw[N],cnt;
    int dep[N],sz[N],top[N],fa[N],son[N];
    char ch[4];
    struct node
    {
    	int l,r;
    	LL add,sum;
    } tr[N<<2];
    
    void add(int u,int v)
    {
    	ne[idx]=head[u];
    	ver[idx]=v;
    	head[u]=idx;
    	idx++;
    }
    
    void dfs1(int u,int father,int depth)
    {
    	sz[u]=1;
    	fa[u]=father;
    	dep[u]=depth;
    	for(int i=head[u]; i!=-1; i=ne[i])
    	{
    		int j=ver[i];
    		if(j==father)continue;
    		dfs1(j,u,depth+1);
    		sz[u]+=sz[j];
    		if(sz[son[u]]<sz[j])   son[u]=j;//sz大小,
    	}
    }
    
    void dfs2(int u,int t)   //t保存u所在当前重链的顶点是谁
    {
    	id[u]=++cnt;//dfs序
    	nw[cnt]=w[u];
    	top[u]=t;
    	if(!son[u])    return;
    	dfs2(son[u],t);
    	for(int i=head[u]; i!=-1; i=ne[i])
    	{
    		int j=ver[i];
    		if(j==fa[u]||j==son[u])continue;
    		dfs2(j,j);
    	}
    }
    
    struct  tree
    {
    	inline void pushup(int p)
    	{
    		tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum;
    	}
    
    	inline void pushdown(int p)
    	{
    		if(tr[p].add)
    		{
    			tr[p<<1].sum+=(tr[p<<1].r-tr[p<<1].l+1)*tr[p].add;
    			tr[p<<1].add+=tr[p].add;
    			tr[p<<1|1].sum+=(tr[p<<1|1].r-tr[p<<1|1].l+1)*tr[p].add;
    			tr[p<<1|1].add+=tr[p].add;
    			tr[p].add=0;
    		}
    	}
    	void build(int p,int l,int r)
    	{
    		tr[p]= {l,r,0,nw[l]};
    		if(l==r)   return;
    		int	mid=(tr[p].l+tr[p].r)/2;
    		build(p<<1,l,mid);
    		build(p<<1|1,mid+1,r);
    		pushup(p);
    	}
    
    	void update(int p,int l,int r,int k)
    	{
    		if(tr[p].l>=l&&tr[p].r<=r)
    		{
    			tr[p].sum+=(tr[p].r-tr[p].l+1)*k;
    			tr[p].add+=k;
    			return ;
    		}
    		pushdown(p);
    		int mid=tr[p].l+tr[p].r>>1;
    		if(l<=mid)	update(p<<1,l,r,k);
    		if(r>mid)	update(p<<1|1,l,r,k);
    		pushup(p);
    	}
    
    
    	LL query(int p,int l,int r)
    	{
    		if(tr[p].l>=l&&tr[p].r<=r)
    		{
    			return tr[p].sum;
    		}
    		pushdown(p);
    		int mid=tr[p].l+tr[p].r>>1;
    		LL ans=0;
    		if(l<=mid)	ans+=query(p<<1,l,r);
    		if(r>mid)	ans+=query(p<<1|1,l,r);
    		return ans;
    	}
    } segment;
    
    
    struct tre
    {
    	void update_path(int u,int v,int k)
    	{
    		while(top[u]!=top[v])
    		{
    			if(dep[top[u]]<dep[top[v]])
    				swap(u,v);
    			segment.update(1,id[top[u]],id[u],k);
    			u=fa[top[u]];
    		}
    		if(dep[u]<dep[v])
    			swap(u,v);
    		segment.update(1,id[v],id[u],k);
    	}
    
    	LL query_path(int u,int v)
    	{
    		LL res=0;
    		while(top[u]!=top[v])
    		{
    			if(dep[top[u]]<dep[top[v]])
    				swap(u,v);
    			res+=segment.query(1,id[top[u]],id[u]);
    			u=fa[top[u]];
    		}
    		if(dep[u]<dep[v])
    			swap(u,v);
    		res+=segment.query(1,id[v],id[u]);
    		return res;
    	}
    
    	void update_tree(int u,int k)
    	{
    		segment.update(1,id[u],id[u]+sz[u]-1,k);
    	}
    
    	LL query_tree(int u)
    	{
    		segment.query(1,id[u],id[u]+sz[u]-1);
    	}
    
    } chain;
    inline int read()
    {
    	int x=0;
    	int f=1;
    	char ch;
    	ch=getchar();
    	while(ch>'9'||ch<'0')
    	{
    		if(ch=='-')f=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9')
    	{
    		x=x*10,x=x+ch-'0';
    		ch=getchar();
    	}
    	return x*f;
    }
    int main()
    {
    	scanf("%d",&n);
    	memset(head,-1,sizeof(head));
    	for(int i=1; i<=n-1; i++)
    	{
    		int a,b;
    		a=read();
    		b=read();
    		a++;
    		b++;
    		add(a,b);
    		add(b,a);
    	}
    	dfs1(1,-1,1);
    	dfs2(1,1) ;
    	segment.build(1,1,n);
    	scanf("%d",&m);
    	for(int i=1; i<=m; i++)
    	{
    		int t,u,v,k;
    		scanf("%s",ch+1);
    		if(ch[1]=='A')
    		{
    			scanf("%d%d%d",&u,&v,&k);
    			{
    				chain.update_path(u+1,v+1,k);
    			}
    		}
    		else
    		{
    			scanf("%d",&u);
    			printf("%lld
    ",chain.query_tree(u+1));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    javascript中实现类似php 的var_dump
    WKWebView与js交互中产生的内存泄漏
    图片按照指定比例裁剪
    php解析json字符串变量总是空白null
    CocoaPods | iOS详细使用说明
    腾讯IM的那些坑
    JS---案例:协议按钮禁用(倒计时)
    JS---另一个定时器:一次性的
    JS---part5 课程介绍 & part4 复习
    JS---案例:美女时钟
  • 原文地址:https://www.cnblogs.com/bangdexuanyuan/p/14001839.html
Copyright © 2011-2022 走看看