洛谷P4315 月下“毛景树” 题解

洛谷P4315 月下“毛景树” 题解

题目链接:P4315 月下“毛景树”

题意:请维护一个数据结构,支持

  1. 改第 k k k 条边的边权
  2. 结点 u u u v v v 路径上的边权改为 k k k
  3. 结点 u u u v v v 路径上的边权增加 k k k
  4. 询问结点 u u u v v v 路径上的边权最大值

一看树链剖分,敲了个板子发现给的是边权

那么就只要把边权转化为点权就可以用线段树维护了

显然把父亲到儿子的边权存在儿子上更好维护

也就是把边权存在深度大的结点

在跳出top[x]!=top[y]循环时

id[x],dep[x]<dep[y]其实是原来 u u u v v vlca,这个lca的边权显然不是 u u u v v v 路径上的边

所以维护id[x]+1

然后就是少见的区间赋值操作,别跟我说ODT,怕被卡

主要难在代码实现上,直接贴了(3.79KB)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define gc() getchar()
#define pc(a) putchar(a)
template<typename T>inline void read(T &k)
{
	char ch=gc();T x=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
	k=x*f;
}
template<typename T>inline void write(T k)
{
	if(k<0){k=-k;pc('-');}
	if(k>9)write(k/10);
	pc(k%10+'0');
}
#define MAXN (int)(1e5+5)
#define Max(a,b) a=max(a,b) 
struct Edge
{
	int u,v,w,next;
}e[MAXN<<1];
int head[MAXN],pos=1;
int n;char tmp[233];
int a[MAXN],t[MAXN],dep[MAXN],id[MAXN],idx;
int fa[MAXN],son[MAXN],sz[MAXN],top[MAXN];
int ans[MAXN<<2],tag1[MAXN<<2],tag2[MAXN<<2];
void addEdge(int u,int v,int w)
{
	e[pos]={u,v,w,head[u]};
	head[u]=pos++;
}
void dfs(int u,int f,int d)
{
	fa[u]=f;dep[u]=d;
	sz[u]=1;int mx=-1;
	for(int i=head[u]; i; i=e[i].next)
	{
		int v=e[i].v;
		if(v==f)continue;
		dfs(v,u,d+1);
		sz[u]+=sz[v];t[v]=e[i].w;
		if(sz[v]>mx)mx=sz[v],son[u]=v;
	}
}
void dfs(int u,int ftop)
{
	id[u]=++idx;a[idx]=t[u];
	top[u]=ftop;
	if(!son[u])return;
	dfs(son[u],ftop);
	for(int i=head[u]; i; i=e[i].next)
	{
		int v=e[i].v;
		if(v==fa[u]||v==son[u])continue;
		dfs(v,v);
	}
}
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
void push_up(int at)
{
	ans[at]=max(ans[ls(at)],ans[rs(at)]);
}
void build(int l,int r,int at)
{
	if(l==r){ans[at]=a[l];return;}
	int mid=(l+r)>>1;
	build(l,mid,ls(at));
	build(mid+1,r,rs(at));
	push_up(at);
	tag1[at]=-1;tag2[at]=0;
}
void proc(int l,int r,int at)
{
	int u=at>>1;
	if(tag1[u]>=0)
	{
		tag1[at]=tag1[u];
		tag2[at]=0;
		ans[at]=tag1[u];
	}
	if(tag2[u]>=0)
	{
		ans[at]+=tag2[u];
		tag2[at]+=tag2[u];
	}
}
void push_down(int l,int r,int at)
{
	int mid=(l+r)>>1;
	proc(l,mid,ls(at));
	proc(mid+1,r,rs(at));
	tag1[at]=-1;tag2[at]=0;
}
void update_cover(int nl,int nr,int l,int r,int k,int at)
{
	if(nl<=l&&r<=nr)
	{
		ans[at]=k;
		tag1[at]=k;
		tag2[at]=0;
		return;
	}
	push_down(l,r,at);
	int mid=(l+r)>>1;
	if(nl<=mid)update_cover(nl,nr,l,mid,k,ls(at));
	if(nr>mid)update_cover(nl,nr,mid+1,r,k,rs(at));
	push_up(at);
}
void update_add(int nl,int nr,int l,int r,int k,int at)
{
	if(nl<=l&&r<=nr)
	{
		ans[at]+=k;
		tag2[at]+=k;
		return;
	}
	push_down(l,r,at);
	int mid=(l+r)>>1;
	if(nl<=mid)update_add(nl,nr,l,mid,k,ls(at));
	if(nr>mid)update_add(nl,nr,mid+1,r,k,rs(at));
	push_up(at);
}
int query(int nl,int nr,int l,int r,int at)
{
	int res=-1;
	if(nl<=l&&r<=nr)
		{return ans[at];}
	push_down(l,r,at);
	int mid=(l+r)>>1;
	if(nl<=mid)Max(res,query(nl,nr,l,mid,ls(at)));
	if(nr>mid)Max(res,query(nl,nr,mid+1,r,rs(at)));
	return res;
}
void addRange(int x,int y,int k)
{
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		update_add(id[top[x]],id[x],1,n,k,1);
		x=fa[top[x]];
	}
	if(id[x]>id[y])swap(x,y);
	update_add(id[x]+1,id[y],1,n,k,1);
}
void coverRange(int x,int y,int k)
{
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		update_cover(id[top[x]],id[x],1,n,k,1);
		x=fa[top[x]];
	}
	if(id[x]>id[y])swap(x,y);
	update_cover(id[x]+1,id[y],1,n,k,1);
}
int qRange(int x,int y)
{
	int res=-1;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		Max(res,query(id[top[x]],id[x],1,n,1));
		x=fa[top[x]];
	}
	if(id[x]>id[y])swap(x,y);
	Max(res,query(id[x]+1,id[y],1,n,1));
	return res;
}
signed main()
{
	read(n);
	for(int i=1,u,v,w; i<n; i++)
	{
		read(u);read(v);read(w);
		addEdge(u,v,w);
		addEdge(v,u,w);
	}
	dfs(1,0,1);dfs(1,1);
	build(1,n,1);int l,r,x,k;
	while(~scanf("%s%lld%lld",tmp,&l,&r))
	{
		if(tmp[0]=='S')break;
		if(tmp[0]=='M')
			write(qRange(l,r)),pc('\n');
		if(tmp[0]=='A')
		{
			read(k);
			addRange(l,r,k);
		}
		if(tmp[1]=='h')
		{
			x=l,k=r;
			x=dep[e[2*x-1].v]<dep[e[2*x].v]?e[x*2].v:e[x*2-1].v;
			update_cover(id[x],id[x],1,n,k,1);
		}
		if(tmp[1]=='o')
		{
			read(k);
			coverRange(l,r,k);
		}
	}
	return 0;
}

转载请说明出处

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值