P4146 序列终结者(Splay树)

给出一个初始为0的序列。

询问区间最大值,并同时支持区间修改和区间翻转。

就正常模仿线段树,给Splay打懒标记即可。

巨大的坑就是要保证虚拟节点,0,1,n+2不对答案产生影响。
这里把他们的权值和区间值全置为负无穷。

//区间修改
//区间反转
//区间求MAX
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
const long long inf=1e18;
int rt,fa[maxn],ch[maxn][2],sz[maxn];
int lz[maxn];//区间翻转标记
long long add_lz[maxn];//区间修改标记
long long c[maxn];//保存区间最大值
long long w[maxn];
int tot;
long long a[maxn];
struct Splay {
	void maintain (int x) {
		sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;
		c[x]=max(w[x],max(c[ch[x][0]],c[ch[x][1]]));
	}
	void pushdown (int x) {
		if (!x) return;
		if (lz[x]) {
			swap(ch[x][0],ch[x][1]);
			lz[ch[x][0]]^=lz[x];
			lz[ch[x][1]]^=lz[x];
			lz[x]=0;
		}
		if (add_lz[x]) {
			if (ch[x][0]){
				c[ch[x][0]]+=add_lz[x];
				w[ch[x][0]]+=add_lz[x];
				add_lz[ch[x][0]]+=add_lz[x];
			}
			if (ch[x][1]){
				c[ch[x][1]]+=add_lz[x];
				w[ch[x][1]]+=add_lz[x];
				add_lz[ch[x][1]]+=add_lz[x];
			}
			add_lz[x]=0;
		}
	}
	bool get (int x) {
		return x==ch[fa[x]][1];
	}
	void rotate (int x) {
		pushdown(x);
		pushdown(fa[x]);
		int y=fa[x];
		int z=fa[y];
		int chk=get(x);
		ch[y][chk]=ch[x][chk^1];
		if (ch[x][chk^1]) {
			fa[ch[x][chk^1]]=y;
		}
		ch[x][chk^1]=y;
		fa[y]=x;
		fa[x]=z;
		if (z) {
			ch[z][y==ch[z][1]]=x;
		}
		maintain(x);
		maintain(y);
	}
	void splay (int x,int ed) {
		for (int f=fa[x];(f=fa[x])!=ed;rotate(x)) {
			if (fa[f]!=ed) {
				rotate(get(x)==get(f)?f:x);
			}
		}
		if (ed==0) rt=x;
	}
	int build (int l,int r,int f) {
		if (l>r) return 0;
		int mid=(l+r)>>1;
		int u=++tot;
		fa[u]=f;
		ch[u][0]=ch[u][1]=lz[u]=0;
		sz[u]=1;
		ch[u][0]=build(l,mid-1,u);
		ch[u][1]=build(mid+1,r,u);
		maintain(u);
		return u;
	}
	int rk (int x) {
		int cur=rt;
		while (1) {
			pushdown(cur);
			if (x<=sz[ch[cur][0]]) {
				cur=ch[cur][0];
			}
			else {
				x-=sz[ch[cur][0]]+1;
				if (!x) return cur;
				cur=ch[cur][1];
			}
		}
		return 0; 
	}
	void rev (int x,int y) {
		int l=x-1;
		int r=y+1;
		l=rk(l);
		r=rk(r);
		splay(l,0);
		splay(r,l);
		int pos=ch[rt][1];
		pos=ch[pos][0];
		lz[pos]^=1;
	}
	void up (int x,int y,int v) {
		int l=x-1;
		int r=y+1;
		l=rk(l);
		r=rk(r);
		splay(l,0);
		splay(r,l);
		int pos=ch[rt][1];
		pos=ch[pos][0];
		c[pos]+=v;
		w[pos]+=v;
		add_lz[pos]+=v;
	}
	long long query (int x,int y) {
		int l=x-1;
		int r=y+1; 
		l=rk(l);
		r=rk(r);
		splay(l,0);
		splay(r,l);
		int pos=ch[rt][1];
		pos=ch[pos][0];
		return c[pos]; 
	}
}splay; 
int main () {
	
	int n,m;
	scanf("%d%d",&n,&m);
	c[0]=w[0]=w[1]=w[n+2]=-inf;
	rt=splay.build(1,n+2,0);
	while (m--) {
		int op;
		scanf("%d",&op);
		if (op==1) {
			int l,r,v;
			scanf("%d%d%d",&l,&r,&v);
			l++,r++;
			splay.up(l,r,v);
		}
		else if (op==2){
			int l,r;
			scanf("%d%d",&l,&r);
			l++,r++;
			splay.rev(l,r);
		}
		else {
			int l,r;
			scanf("%d%d",&l,&r);
			l++,r++;
			long long ans=splay.query(l,r);
			printf("%lld\n",ans);
		}
	}
}

P4146 序列终结者(Splay树)

上一篇:Layui文本框限制正整数


下一篇:单片机:蜂鸣器单响