4034. [HAOI2015]树上操作树链剖分

Posted Refun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了4034. [HAOI2015]树上操作树链剖分相关的知识,希望对你有一定的参考价值。

Description

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

Input

第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 
行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

Output

对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

Sample Input

5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3

Sample Output

6
9
13

HINT

 对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。

 

一道裸的树剖却因为建树时候的sb错误搞了半天
不想说什么(不过这个题好像会炸int)

 

 

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
#define MAXN (100000+50)
using namespace std;
LL Tree[MAXN];
LL T_num[MAXN];
LL Depth[MAXN];
LL Father[MAXN];
LL Sum[MAXN];
LL Son[MAXN];
LL Top[MAXN];
LL a[MAXN];
LL n,m,u,v,sum;
LL head[MAXN],num_edge;
struct node1
{
	LL val;
	LL add;
} Segt[MAXN*4];
struct node2
{
	LL to;
	LL next;
} edge[MAXN*2];
void add(LL u,LL v)
{
	edge[++num_edge].to=v;
	edge[num_edge].next=head[u];
	head[u]=num_edge;
}

void Dfs1(LL x)
{
	Sum[x]=1;
	Depth[x]=Depth[Father[x]]+1;
	for (LL i=head[x]; i!=0; i=edge[i].next)
		if (edge[i].to!=Father[x])
		{
			Father[edge[i].to]=x;
			Dfs1(edge[i].to);
			Sum[x]+=Sum[edge[i].to];
			if (Son[x]==0 || (Sum[Son[x]]<Sum[edge[i].to]))
				Son[x]=edge[i].to;
		}
}

void Dfs2(LL x,LL tp)
{
	T_num[x]=++sum;
	Tree[sum]=a[x];
	Top[x]=tp;
	if (Son[x])
		Dfs2(Son[x],tp);
	for (LL i=head[x]; i!=0; i=edge[i].next)
		if (edge[i].to!=Son[x] && edge[i].to!=Father[x])
			Dfs2(edge[i].to,edge[i].to);
}

void Pushdown(LL node,LL l,LL r)
{
	if (Segt[node].add!=0)
	{
		LL mid=(l+r)/2;
		Segt[node*2].val+=Segt[node].add*(mid-l+1);
		Segt[node*2+1].val+=Segt[node].add*(r-mid);
		Segt[node*2].add+=Segt[node].add;
		Segt[node*2+1].add+=Segt[node].add;
		Segt[node].add=0;
	}
}

void Build(LL node,LL l,LL r)
{
	if (l==r)
		Segt[node].val=Tree[l];
	else
	{
		LL mid=(l+r)/2;
		Build(node*2,l,mid);
		Build(node*2+1,mid+1,r);
		Segt[node].val=Segt[node*2].val+Segt[node*2+1].val;
	}
}

void Update(LL node,LL l,LL r,LL l1,LL r1,LL k)
{
	if (l>r1 || r<l1)
		return;
	if (l1<=l && r<=r1)
	{
		Segt[node].val+=(r-l+1)*k;
		Segt[node].add+=k;
		return;
	}
	Pushdown(node,l,r);
	LL mid=(l+r)/2;
	Update(node*2,l,mid,l1,r1,k);
	Update(node*2+1,mid+1,r,l1,r1,k);
	Segt[node].val=Segt[node*2].val+Segt[node*2+1].val;
}

LL Query(LL node,LL l,LL r,LL l1,LL r1)
{
	if (l>r1 || r<l1)
		return 0;
	if (l1<=l && r<=r1)
		return Segt[node].val;
	Pushdown(node,l,r);
	LL mid=(l+r)/2;
	return Query(node*2,l,mid,l1,r1)+Query(node*2+1,mid+1,r,l1,r1);
}

LL Get(LL x)
{
	LL ans=0;
	while (x!=0)
	{
		ans+=Query(1,1,n,T_num[Top[x]],T_num[x]);
		x=Father[Top[x]];
	}
	return ans;
}

int main()
{
	scanf("%lld%lld",&n,&m);
	for (LL i=1; i<=n; ++i)
		scanf("%lld",&a[i]);
	for (LL i=1; i<=n-1; ++i)
	{
		scanf("%lld%lld",&u,&v);
		add(u,v);
		add(v,u);
	}
	Dfs1(1);
	Dfs2(1,1);
	Build(1,1,n);
	for (LL i=1; i<=m; ++i)
	{
		LL p,x,y;
		scanf("%lld",&p);
		if (p==1)
		{
			scanf("%lld%lld",&x,&y);
			Update(1,1,n,T_num[x],T_num[x],y);
		}
		if (p==2)
		{
			scanf("%lld%lld",&x,&y);
			Update(1,1,n,T_num[x],T_num[x]+Sum[x]-1,y);
		}
		if (p==3)
		{
			scanf("%lld",&x);
			printf("%lld\n",Get(x));
		}
	}
}

 

以上是关于4034. [HAOI2015]树上操作树链剖分的主要内容,如果未能解决你的问题,请参考以下文章

4034. [HAOI2015]树上操作树链剖分

bzoj 4034: [HAOI2015]树上操作——树链剖分

BZOJ 4034[HAOI2015]树上操作(树链剖分)

BZOJ 4034: [HAOI2015]T2 树链剖分

4034: [HAOI2015]树上操作

数据结构(树链剖分):BZOJ 4034: [HAOI2015]T2