跳跃的小怪兽——splay序列操作

Description

n个小怪兽站成一行跳来跳去。每次跳跃操作是以下两种形式之一:
a L b:从左到右第a个小怪兽跳过它左边的b个小怪兽,然后落地。
a D b:从左到右第a个小怪兽跳过它右边的b个小怪兽,然后落地。
  小怪兽有身高差异,因此在跳跃时需要注意不要碰到其他小怪兽的头。具体来说,每次跳跃的高度等于越过的所有小怪兽的身高的最大值。
  你的任务是计算出每次跳跃的高度。

Input

  输入第一行包含两个整数n(2<=n<=100,000), J(1<=J<=100,000),表示小怪兽的个数和跳跃的个数。
  第二行有n个小于100,000的正整数,即各个小怪兽的身高(从左到右)。
  以下J行每行描述一次跳跃(按照实际跳跃顺序排列),格式为”a L b”或者”a D b”,含义如图所述。跳跃总是合法的,即往左跳时,左数第a个小怪兽左边至少有b个小怪兽;往右跳时,左数第a个小怪兽右边至少有b个小怪兽。

Output

  对于每次跳跃,输出一行,包含本次跳跃的高度。

Sample Input

9 3

5 3 8 4 9 3 7 4 2

2 D 3

8 L 2

5 D 2

Sample Output

9

7

4

Hint

【样例解释】
  第一次跳:5 3 8 4 9 3 7 4 2 -> 5 8 4 9 3 3 7 4 2,max{8,4,9}=9
  第二次跳:5 8 4 9 3 3 7 4 2 -> 5 8 4 9 3 4 3 7 2,max{3,7}=7
  第三次跳:5 8 4 9 3 4 3 7 2 -> 5 8 4 9 4 3 3 7 2,max{4,3}=4

删除,插入,区间查询。

再一个一道题一整天系列,经过changxv大佬的提醒,发现我之前的插入,删除操作写的都很蠢,而且对于这道题竟然会挂掉,原来合理利用BST中序的性质(参见文艺平衡树),可以很好地实现插入和删除。

我们要在x位置插入,现将x-1转到根,再将x转到x-1的右儿子,由中序遍历性质,x没有左儿子,我们只需将新建节点作为x的左儿子,新节点就成为了序列中的x位置,而x就变成了x+1位置。

删除同理。

#include<bits/stdc++.h>
using namespace std;
inline int Getint(){register int re=0,f=1;register char c;while(c=getchar(),(c>='0'&&c<='9')^1)f=c^'-';while(re=(re<<1)+(re<<3)+(c^48),c=getchar(),(c>='0'&&c<='9'));return f?re:-re;}
inline char Getchar(){char c=getchar();while(c^'D'&&c^'L')c=getchar();return c;}
#define Inc(i,L,R) for(register int i=(L);i<=(R);++i)
#define Red(j,R,L) for(register int j=(R);j>=(L);--j)
const int N = 2e5+10;
int n,m,a[N/2];
struct Splay{
	int k[N],Max[N],siz[N];
	int rt,cnt,p[N],ch[N][2];
	#define Ls(v) ch[v][0]
	#define rs(v) ch[v][1]
	inline void maintain(int x){
		siz[x]=siz[Ls(x)]+siz[rs(x)]+1;
		Max[x]=max(k[x],max(Max[Ls(x)],Max[rs(x)]));
	}
	inline int build(int L,int r){
		if(L>r)return 0;
		int x=++cnt,Mid=L+r>>1;
		k[x]=Max[x]=a[Mid];
		siz[x]=1;
		Ls(x)=build(L,Mid-1);
		rs(x)=build(Mid+1,r);
		if(Ls(x))p[Ls(x)]=x;
		if(rs(x))p[rs(x)]=x;
		maintain(x);
		return x;
	}
	inline void rot(int x){
		int f=p[x],gf=p[f],type=rs(f)==x,son=ch[x][!type];
		ch[p[son]=f][type]=son,maintain(f);
		ch[p[f]=x][!type]=f,maintain(x);
		ch[p[x]=gf][rs(gf)==f]=x;
	}
	inline void splay(int x,int goal){//旋转在目标的下面 
		while(p[x]^goal){
			if((p[p[x]]^goal)&&((rs(p[p[x]])==p[x])==(rs(p[x])==x)))rot(p[x]);
			rot(x);
		}
		if(!goal)rt=x;
	}
	inline int FindPos(int Size){
		int x=rt;
		while(1){
			if(siz[Ls(x)]+1==Size)break;
			if(Size>siz[Ls(x)]+1)Size-=siz[Ls(x)]+1,x=rs(x);
			else x=Ls(x);
		}
		return x;
	}
	inline void Delete(int kp){
		int L=FindPos(kp-1),r=FindPos(kp+1);
		splay(L,0),splay(r,rt);
		Ls(r)=0;
		maintain(r),maintain(L);
	}
	inline void Insert(int kp,int v){
		int L=FindPos(kp-1),r=FindPos(kp);
		splay(L,0),splay(r,rt);
		siz[++cnt]=1;
		k[cnt]=Max[cnt]=v;
		p[Ls(r)=cnt]=r;
		maintain(cnt),maintain(r),maintain(L);
	}
	inline void update(int A,int b,bool opt){
		int New,Tmpk;
		if(opt==0){
			int Ap=FindPos(A),bp=FindPos(A+b+1);
			splay(Ap,0),splay(bp,rt);
			cout<<Max[Ls(bp)]<<"\n";
			New=A+b;
		}else {
			int Ap=FindPos(A-b-1),bp=FindPos(A);
			splay(Ap,0),splay(bp,rt);
			cout<<Max[Ls(bp)]<<"\n";
			New=A-b;
		}
		Tmpk=k[FindPos(A)];
		Delete(A);
		Insert(New,Tmpk);
	}
}sp;
inline void init(){
	n=Getint(),m=Getint();
	a[1]=-0x3f3f3f3f;//加哨兵 
	Inc(i,2,n+1)a[i]=Getint();
	a[n+2]=-0x3f3f3f3f;
	sp.rt=sp.build(1,n+2);
}
inline void solv(){
	Inc(i,1,m){
		int A=Getint();char c=Getchar();int b=Getint();
		if(c=='D')sp.update(A+1,b,0);
		else sp.update(A+1,b,1);
	}
}
int main(){
	init();
	solv();
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值