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\n",chain.query_tree(u+1));
		}
	}
	return 0;
}
posted @ 2020-11-18 20:03  邦的轩辕  阅读(149)  评论(0编辑  收藏  举报