[TJOI2015]旅游

这篇博客主要讨论了如何利用动态树(也称作线段树)解决区间数据维护的问题,特别是在处理区间最大值、最小值以及区间加法更新的情况下。代码实现中展示了如何进行节点旋转、路径压缩以及懒惰标记等操作,以优化查询和更新的效率。文章通过一个具体的实例展示了如何处理区间翻转和更新操作,并在最后给出了相关算法的测试用例。
摘要由CSDN通过智能技术生成

很容易想到要用动态树来维护。
不过这一道题我被恶心了一下,主要是翻转操作会影响结果,所以应该同时维护从左到右和从右到左的结果。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
template<typename T>inline void qr(T &x){
	x=0;int f=0;char s=getchar();
	while(s<'0'||'9'<s)f|=s=='-',s=getchar();
	while('0'<=s&&s<='9')x=x*10+s-48,s=getchar();
	x=f?-x:x;
}
#define lc ch[x][0]
#define rc ch[x][1]
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
const int mxn=5e4+10;
int d[mxn],fa[mxn],ch[mxn][2],lmax[mxn],rmax[mxn],dmx[mxn],dmn[mxn];
bool rv[mxn];int lazy[mxn],sta[mxn];
bool nrt(int x){return ls(fa[x])==x||rs(fa[x])==x;}
void crv(int x){
	if(!x)return;
	swap(lc,rc);rv[x]^=1;
	swap(lmax[x],rmax[x]);
}
void add(int x,int val){
	if(!x)return;
	d[x]+=val,dmx[x]+=val,dmn[x]+=val;
	lazy[x]+=val;
}
void pushdown(int x){
	if(rv[x])
		crv(lc),crv(rc),rv[x]=0;
	if(lazy[x])
		add(lc,lazy[x]),add(rc,lazy[x]),lazy[x]=0;
}
void update(int x){
	lmax[x]=max(max(lmax[lc],lmax[rc]),max(d[x],dmx[rc])-min(d[x],dmn[lc]));
	rmax[x]=max(max(rmax[lc],rmax[rc]),max(d[x],dmx[lc])-min(d[x],dmn[rc]));
	dmx[x]=max(max(dmx[lc],dmx[rc]),d[x]);
	dmn[x]=min(min(dmn[lc],dmn[rc]),d[x]);
}
void rotate(int x){
	int y=fa[x],z=fa[y],w=rs(y)==x;
	if(nrt(y))ch[z][rs(z)==y]=x;fa[x]=z;
	fa[ch[y][w]=ch[x][1-w]]=y;
	ch[x][1-w]=y;fa[y]=x;
	update(y);
}
void splay(int p){
	int x=p,tp=0;
	sta[++tp]=x;
	while(nrt(x))sta[++tp]=x=fa[x];
	while(tp)pushdown(sta[tp--]);x=p;
	while(nrt(x)){
		int y=fa[x],z=fa[y];
		if(nrt(y))
			(rs(z)==y)^(rs(y)==x)?rotate(x):rotate(y);
		rotate(x);
	}
	update(x);
}
void access(int x){
	for(int y=0;x;x=fa[y=x])
		splay(x),rc=y,update(x);
}
void makeroot(int x){
	access(x);
	splay(x);
	crv(x);
}
void link(int x,int y){
	makeroot(x);
	fa[x]=y;
}
void split(int x,int y){
	makeroot(x);
	access(y);
	splay(y);
}
int main(){
//	freopen("2.in","r",stdin);
//	freopen("2.out","w",stdout);
	int n;qr(n);
	for(int i=1;i<=n;i++){
		qr(d[i]);
		dmx[i]=dmn[i]=d[i];
	}
	dmn[0]=1e9+10;
	for(int i=1;i<n;i++){
		int x,y;qr(x),qr(y);
		link(x,y);
	}
	int q;qr(q);
	while(q--){
		int x,y,v;qr(x),qr(y),qr(v);
		split(x,y);
		printf("%d\n",lmax[y]);
		add(y,v);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值