西雅图
18:14发布
西雅图
18:14发布
8°
东南风 4级
空气质量 无
相对湿度 90%
今天
中雨
6°/11°
周四
中雨
3°/10°
周五
2°/10°

洛谷 P3178 [HAOI2015]树上操作

题目链接:洛谷P3178 [HAOI2015]树上操作

这篇题解原发于我的blog

这是一道树链剖分的板子题,纯粹的模板题事实上模板题比他难
事实上只要做过这道题P3384 【模板】树链剖分就可以我把题目难度提升了

毕竟我是刚切完板子题的人,初生牛犊不怕虎,直接再打一遍练练手被逼的

记住因为这题没有提供取模的数,因为106×105>2311,所以可能会爆int您要是想作死的话也可以,所以这道题只要懒标记和线段树上的累加long long使用即可,这样我就过了这道假紫题难题

#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
#define re register
#define ls (k<<1)
#define rs (k<<1|1)
template<typename T>
inline void read(T&x)
{
	x=0;
	char s=getchar();
	bool f=false;
	while(!(s>='0'&&s<='9'))
	{
		if(s=='-')
			f=true;
		s=getchar();
	}
	while(s>='0'&&s<='9')
	{
		x=(x<<1)+(x<<3)+s-'0';
		s=getchar();
	}
	if(f)
		x=(~x)+1;
	return;
}
const int N=1e5+10;
#define M (N<<1)
struct Edge
{
	int next,to;
} edge[M];
int num_edge,head[N];
int n,m,cnt,rk[N],id[N],dep[N],fa[N],top[N],son[N],size[N],num[N];
ll res;
struct Tree
{
	int l,r,size;
	ll lazy,sum;
} tree[N<<2];
inline void add_edge(int from,int to)
{
	edge[++num_edge].next=head[from];
	edge[num_edge].to=to;
	head[from]=num_edge;
}
inline void dfs1(int u,int f)
{
	dep[u]=dep[f]+1;
	fa[u]=f;
	size[u]=1;
	for(re int i=head[u]; i; i=edge[i].next)
	{
		int &v=edge[i].to;
		if(v==f)
			continue;
		dfs1(v,u);
		size[u]+=size[v];
		if(size[v]>size[son[u]])
			son[u]=v;
	}
}
inline void dfs2(int u,int tp)
{
	id[u]=++cnt;
	rk[cnt]=u;
	top[u]=tp;
	if(!son[u])
		return;
	dfs2(son[u],tp);
	for(re int i=head[u]; i; i=edge[i].next)
	{
		int &v=edge[i].to;
		if(id[v])
			continue;
		dfs2(v,v);
	}
	return;
}
inline void pushup(int k)
{
	tree[k].sum=tree[ls].sum+tree[rs].sum;
}
inline void pushdown(int k)
{
	if(!tree[k].lazy)
		return;
	tree[ls].lazy+=tree[k].lazy;
	tree[rs].lazy+=tree[k].lazy;
	tree[ls].sum+=tree[k].lazy*tree[ls].size;
	tree[rs].sum+=tree[k].lazy*tree[rs].size;
	tree[k].lazy=0;
}
inline void build(int k,int l,int r)
{
	tree[k].l=l;
	tree[k].r=r;
	tree[k].size=r-l+1;
	if(l==r)
	{
		tree[k].sum=num[rk[l]];
		return;
	}
	int mid=l+r>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	pushup(k);
	return;
}
inline void update(int k,int l,int r,int val)
{
	if(l<=tree[k].l&&tree[k].r<=r)
	{
		tree[k].sum+=(ll)val*tree[k].size;
		tree[k].lazy+=val;
		return;
	}
	pushdown(k);
	int mid=(tree[k].l+tree[k].r)>>1;
	if(l<=mid)
		update(ls,l,r,val);
	if(mid<r)
		update(rs,l,r,val);
	pushup(k);
	return;
}
inline void query(int k,int l,int r)
{
	if(l<=tree[k].l&&tree[k].r<=r)
	{
		res+=tree[k].sum;
		return;
	}
	pushdown(k);
	int mid=(tree[k].l+tree[k].r)>>1;
	if(l<=mid)
		query(ls,l,r);
	if(mid<r)
		query(rs,l,r);
}
inline ll ask(int x,int y)
{
	ll ans=0ll;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])
			swap(x,y);
		res=0;
		query(1,id[top[x]],id[x]);
		ans+=res;
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])
		swap(x,y);
	res=0;
	query(1,id[x],id[y]);
	ans+=res;
	return ans;
}
int main()
{
	read(n),read(m);
	for(re int i=1; i<=n; ++i)
		read(num[i]);
	for(re int i=1,x,y; i<n; ++i)
	{
		read(x),read(y);
		add_edge(x,y);
		add_edge(y,x);
	}
	dfs1(1,0);
	dfs2(1,1);
	build(1,1,n);
	for(re int i=1,opt,x,y; i<=m; ++i)
	{
		read(opt);
		if(opt==1)
		{
			read(x),read(y);
			update(1,id[x],id[x],y);
		}
		else if(opt==2)
		{
			read(x),read(y);
			update(1,id[x],id[x]+size[x]-1,y);
		}
		else if(opt==3)
		{
			read(x);
			printf("%lld\n",ask(1,x));
		}
	}
	return 0;
}

马蜂差评

作者:蒟蒻wjr
欢迎任何形式的转载,但请务必注明出处。
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。

posted @   蒟蒻wjr  阅读(181)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?

点击右上角即可分享
微信分享提示