【Codevs3306】水果姐逛水果街Ⅲ 树链剖分

本文介绍了一种使用线段树实现的ZKW算法,该算法能够有效地处理区间查询和更新操作。通过具体代码展示了如何初始化线段树、进行单点更新、区间查询等关键步骤,并结合树状结构进行节点维护,适用于解决复杂的数据结构问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

改!了!好!多!天!

线段树尝试了下zkw,也算有所收获

注释有空再加

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define pb push_back 
const int inf=1047483647;
int n,m,fa[200010],top[200010],v[200010],w[200010],siz[200010],son[200010],f[1000010][4],ans,maxp,cntw,dep[200010],maxv,minv;
vector<int> a[200010];
void init(){
	for (maxp=1;maxp<=n+2;maxp<<=1);
	f[maxp][0]=-inf;f[maxp][1]=inf;
	f[maxp*2-1][0]=-inf;f[maxp*2-1][1]=inf;
}
void dfs1(int ro){
	int y;
	siz[ro]=1;son[ro]=0;
	for (int i=0;i<a[ro].size();i++) {
		y=a[ro][i];
		if (y==fa[ro]) continue;
		fa[y]=ro;dep[y]=dep[ro]+1;dfs1(y);
		siz[ro]+=siz[y];
		if (siz[y]>siz[son[ro]]) son[ro]=y;
	} 
	return ;
}
void dfs2(int ro){
	int y;
	if (ro>1) w[ro]=++cntw;
	if (son[ro]) {
		top[son[ro]]=top[ro];
		dfs2(son[ro]);	
	}
	for (int i=0;i<a[ro].size();i++){
		y=a[ro][i];
		if (y==son[ro]||y==fa[ro]) continue;
		top[y]=y;dfs2(y);
	}
}
void zkw_ins_single(int pos,int value){
	int tmp=maxp+pos;
	f[tmp][0]=value;f[tmp][1]=value;f[tmp][2]=f[tmp][3]=0;
	tmp>>=1;
	for (;tmp>=1;tmp>>=1){
		f[tmp][0]=max(f[tmp*2][0],f[tmp*2+1][0]);
		f[tmp][1]=min(f[tmp*2][1],f[tmp*2+1][1]);
		f[tmp][2]=max(f[tmp*2][0]-f[tmp*2+1][1],max(f[tmp*2][2],f[tmp*2+1][2]));
		f[tmp][3]=max(f[tmp*2+1][0]-f[tmp*2][1],max(f[tmp*2][3],f[tmp*2+1][3]));
	}
}
int zkw_query(int ty,int l,int r){
	l=maxp+l-1;r=maxp+r+1;
	int tmp,tmp1,tmp2;
	if (ty==0) tmp=inf;
	else tmp=-inf;
	tmp1=-inf;tmp2=inf;
	for (;r-l>1;l>>=1,r>>=1){
		if (~l&1) ans=max(ans,f[l+1][2+ty]);
		if (r&1) ans=max(ans,f[r-1][2+ty]);
		if (ty==0) {
			if (~l&1) {
				tmp=min(tmp,f[l+1][1]);
				ans=max(ans,tmp1-f[l+1][1]);
				tmp1=max(tmp1,f[l+1][0]);
			}
			if (r&1) {
				tmp=min(tmp,f[r-1][1]);
				ans=max(ans,f[r-1][0]-tmp2);
				tmp2=min(tmp2,f[r-1][1]);	
			}
			}
		else {
			if (r&1) {
				tmp=max(tmp,f[r-1][0]);
				ans=max(ans,tmp1-f[r-1][1]);
				tmp1=max(tmp1,f[r-1][0]);
			}
			if (~l&1) {
				tmp=max(tmp,f[l+1][0]);
				ans=max(ans,f[l+1][0]-tmp2);
				tmp2=min(tmp2,f[l+1][1]);	
			}
		}
		if (~l&1) {
			ans=max(ans,f[l+1][0]-minv);
			ans=max(ans,maxv-f[l+1][1]);
		}
		if (r&1){
			ans=max(ans,f[r-1][0]-minv);
			ans=max(ans,maxv-f[r-1][1]);
		}
	}
	ans=max(ans,tmp1-tmp2);
	return tmp;
}

void query(int x,int y){
	ans=0;maxv=-inf;minv=inf;
	int d=0;
	while (x!=y){
		if (top[x]==top[y]){
			if (dep[x]>dep[y]){
				swap(x,y);d^=1;
			}
			if (d==0) minv=min(minv,zkw_query(0,w[x]+1,w[y]));
			else maxv=max(maxv,zkw_query(1,w[x]+1,w[y]));
			y=x;break;
		}
		if (dep[top[x]]>dep[top[y]]){
			swap(x,y);d^=1;
		}
		if (top[y]==y){
			if (d==0) minv=min(minv,v[y]);
			else maxv=max(maxv,v[y]);
			ans=max(ans,max(maxv-v[y],v[y]-minv));
			y=fa[y];continue;
		}
		if (d==0) minv=min(minv,zkw_query(0,w[top[y]]+1,w[y]));
		else maxv=max(maxv,zkw_query(1,w[top[y]]+1,w[y]));
		y=top[y];
	}
	maxv=max(maxv,v[x]);minv=min(minv,v[x]);
	ans=max(ans,maxv-minv);
}
int main(){
	scanf("%d",&n);
	init();
	for (int i=1;i<=n;i++) scanf("%d",&v[i]);
	for (int i=1;i<=n;i++) v[i]=-v[i];
	int x,y,z;
	for (int i=1;i<n;i++) {
		scanf("%d%d",&x,&y);
		a[x].pb(y);a[y].pb(x);
	}
	dep[1]=1;
	dfs1(1);
	top[1]=1;
	dfs2(1);
	for (int i=2;i<=n;i++) if (w[i]) zkw_ins_single(w[i],v[i]);
	//for (int i=1;i<=n;i++) printf("%d %d %d %d %d\n",i,fa[i],top[i],w[i],v[i]);
	scanf("%d",&m);
	for (int i=1;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		if (x==0){
			v[y]=-z;
			if (w[y]) zkw_ins_single(w[y],v[y]);
		}
		else if (x==1){
			query(y,z);
			printf("%d\n",ans);	
		}
	}
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值