[HAOI2015]树上操作题解

[HAOI2015]树上操作题解

洛谷题目链接

一句话题意

在有权值得树上实现单点修改,和某个子树所有点修改,加上路径权值和的查询


基本上看到题就能想出怎么做的了,很明显的树剖加线段树维护,再求个lca即可,甚至一个端点都确定了。


题解

先进行两次dfs,对树进行重链剖分,这样可以使树在各个小区间上是有序的,方便用线段树维护。

然后建树,在修改时,将单点修改看作区间修改即可,唯二需要注意的是不论懒标记还是sum区间和都是在原来权值上加,即赋值时为“+=”而不是“=”,并且需要开longlong


标程


#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MN=2e6+100;
int n,m,cnt;
int w[MN],head[MN];
struct node{
	int nxt,to;	
}e[MN<<1];
inline void add(int a,int b){
	e[++cnt].nxt=head[a],head[a]=cnt,e[cnt].to=b;
}
int dep[MN],fa[MN],son[MN],siz[MN];
void dfs1(int now,int pre){
	fa[now]=pre;
	siz[now]=1;
	dep[now]=dep[pre]+1;
	for(int i=head[now];i;i=e[i].nxt){
		int to=e[i].to;
		if(to==pre)continue;
		dfs1(to,now);
		siz[now]+=siz[to];
		if(siz[to]>siz[son[now]]){
			son[now]=to;
		}
	}
}
int top[MN],dfn[MN],tot,name[MN];
void dfs2(int now,int tp){
	top[now]=tp;
	dfn[now]=++tot;
	name[tot]=now;
	if(son[now]){
		dfs2(son[now],tp);
	}
	for(int i=head[now];i;i=e[i].nxt){
		int to=e[i].to;
		if(to==fa[now]||to==son[now])continue;
		dfs2(to,to);
	}
}
int tag[MN];
struct tree{
	int l,r,sum;
}t[MN<<2];
inline void pushup(int id){
	t[id].sum=t[id<<1].sum+t[id<<1|1].sum;
}
inline void pushdown(int id){
	if(tag[id]==0)return;
	t[id<<1].sum+=(t[id<<1].r-t[id<<1].l+1)*tag[id],tag[id<<1]+=tag[id];
	t[id<<1|1].sum+=(t[id<<1|1].r-t[id<<1|1].l+1)*tag[id],tag[id<<1|1]+=tag[id];
	tag[id]=0;
}
void build(int id,int l,int r){
	t[id].l=l,t[id].r=r;
	if(l==r){
		t[id].sum=w[name[l]];
		return;
	}
	int mid=(l+r)>>1;
	build(id<<1,l,mid),build(id<<1|1,mid+1,r);
	pushup(id);
}
void update(int id,int l,int r,int a){
	if(t[id].l>=l&&t[id].r<=r){
		tag[id]+=a;
		t[id].sum+=(t[id].r-t[id].l+1)*a;
		return;
	}
	int mid=(t[id].r+t[id].l)>>1;
	pushdown(id);
	if(l<=mid)update(id<<1,l,r,a);
	if(r>=mid+1)update(id<<1|1,l,r,a);
	pushup(id);
}
int get_sum(int id,int l,int r){
	if(t[id].l>=l&&t[id].r<=r){
		return t[id].sum;
	}
	int mid=(t[id].r+t[id].l)>>1,ans=0;
	pushdown(id);
	if(l<=mid)ans+=get_sum(id<<1,l,r);
	if(r>=mid+1)ans+=get_sum(id<<1|1,l,r);
	return ans;
}
int query(int x,int y){
	int ans=0;
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		ans+=get_sum(1,dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	}
	if(dep[x]<dep[y])swap(x,y);
	ans+=get_sum(1,dfn[y],dfn[x]);
	return ans;
}
signed main(){
	//freopen("haoi2015.in","r",stdin);
	//freopen("haoi2015.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;++i)scanf("%lld",&w[i]);	
	for(int i=1,a,b;i<n;++i)scanf("%lld%lld",&a,&b),add(a,b),add(b,a);
	dfs1(1,0);
	dfs2(1,1);
	build(1,1,n);
	while(m--){
		int op,x,a;
		scanf("%lld%lld",&op,&x);
		if(op==1){
			scanf("%lld",&a);
			update(1,dfn[x],dfn[x],a);
		}
		else if(op==2){
			scanf("%lld",&a);
			update(1,dfn[x],dfn[x]+siz[x]-1,a);
		}
		else{
			printf("%lld\n",query(1,x));
		}
	}	
	return 0;
}

posted @ 2021-08-03 16:43  fanner_rick  阅读(81)  评论(0)    收藏  举报