线段树套平衡树基础模板

 P3380 【模板】二逼平衡树(树套树)

要开O2才能过T_T

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=2147483647;
const int maxn=5e4+5;
//il int Add(ll &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
int n,m,a[maxn];
int rt[maxn*25],tot=0;
namespace SP {
	int ch[maxn*25][2],val[maxn*25],cnt[maxn*25],par[maxn*25],sz[maxn*25];

	il void pushup(int x) {
		sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x];
	}
	il bool ws(int x) {
		return ch[par[x]][1]==x;
	}
	il void rotate(int x) {
		int f=par[x],ff=par[f],k=ws(x),w=ch[x][k^1];
		ch[f][k]=w,par[w]=f;
		ch[ff][ws(f)]=x,par[x]=ff;
		ch[x][k^1]=f,par[f]=x;
		pushup(f),pushup(x);
	}
	il void splay(int i,int x,int goal=0) {
		while(par[x]!=goal) {
			int f=par[x],ff=par[f];
			if(ff!=goal) {
				if(ws(x)==ws(f)) rotate(f);
				else rotate(x);
			}
			rotate(x);
		}
		if(!goal) rt[i]=x;
	}
	il void Find(int i,int x) {
		int cur=rt[i];
		while(ch[cur][x>val[cur]] && x!=val[cur]) {
			cur=ch[cur][x>val[cur]];
		}
		splay(i,cur);
	}
	il void Insert(int i,int x) {
		int cur=rt[i],p=0;
		if(rt[i]==0) {
			cur=rt[i]=++tot;
			val[cur]=x,sz[cur]=cnt[cur]=1;
			ch[cur][1]=ch[cur][0]=0,par[cur]=0;
			return ;
		}
		while(cur && val[cur]!=x) {
			p=cur;
			cur=ch[cur][x>val[cur]];
		}
		if(cur) cnt[cur]++;
		else {
			cur=++tot;
			if(p) ch[p][x>val[p]]=cur;
			ch[cur][0]=ch[cur][1]=0;
			par[cur]=p,val[cur]=x;
			cnt[cur]=sz[cur]=1;
		}
		splay(i,cur);
	}
	il int Rank(int i,int x) {
		Find(i,x);
		return sz[ch[rt[i]][0]]+(val[rt[i]]<x?cnt[rt[i]]:0);
	}
	il int Pre(int i,int x) {
		Find(i,x);
		if(val[rt[i]]<x) return rt[i];
		int cur=ch[rt[i]][0];
		while(ch[cur][1]) cur=ch[cur][1];
		return cur;
	}
	il int Back(int i,int x) {
		Find(i,x);
		if(val[rt[i]]>x) return rt[i];
		int cur=ch[rt[i]][1];
		while(ch[cur][0]) cur=ch[cur][0];
		return cur;
	}
	il int Prenum(int i,int x) {
		return val[Pre(i,x)];
	}
	il int Backnum(int i,int x) {
		return val[Back(i,x)];
	}
	il void Remove(int i,int x) {
		int last=Pre(i,x),beh=Back(i,x);
		splay(i,last),splay(i,beh,last);
		int del=ch[beh][0];
		if(cnt[del]>1) {
			cnt[del]--;
			splay(i,del);
		} 
		else ch[beh][0]=0;
	}
}
namespace Seg {
	il void spbuild(int l,int r,int nrt) {
		SP::Insert(nrt,-inf),SP::Insert(nrt,inf);
		for(int i=l; i<=r; ++i) SP::Insert(nrt,a[i]);
	}
	il void build(int l,int r,int nrt) {
		spbuild(l,r,nrt);
		if(l==r) return;
		int mid=(l+r)>>1;
		build(l,mid,nrt<<1);
		build(mid+1,r,nrt<<1|1);
	}
	il void update(int l,int r,int x,int C,int nrt) {
		SP::Remove(nrt,a[x]);
		SP::Insert(nrt,C);
		if(l==r) return;
		int mid=(l+r)>>1;
		if(x<=mid) update(l,mid,x,C,nrt<<1);
		else update(mid+1,r,x,C,nrt<<1|1);
	}
	il int qRank(int L,int R,int l,int r,int nrt,int k){
		if(L<=l && R>=r)	return SP::Rank(nrt,k)-1;
		int mid=(l+r)>>1,num=0;
		if(L<=mid) num+=qRank(L,R,l,mid,nrt<<1,k);
		if(R>mid) num+=qRank(L,R,mid+1,r,nrt<<1|1,k);
		return num;
	} 
	il int qRank(int L,int R,int k){
		return qRank(L,R,1,n,1,k)+1;
	}
	il int qPre_Back(int L,int R,int l,int r,int nrt,int k,bool fg){
//		fg==1?Pre:Back
		int ans=fg?-inf:inf;
		if(L<=l && R>=r){
			fg?(ans=max(ans,SP::Prenum(nrt,k))):(ans=min(ans,SP::Backnum(nrt,k)));
			return ans;
		}
		int mid=(l+r)>>1;
		if(L<=mid){
			 if(fg) ans=max(ans,qPre_Back(L,R,l,mid,nrt<<1,k,fg));
			 else ans=min(ans,qPre_Back(L,R,l,mid,nrt<<1,k,fg));
		}
		if(R>mid){
			if(fg) ans=max(ans,qPre_Back(L,R,mid+1,r,nrt<<1|1,k,fg));
			else ans=min(ans,qPre_Back(L,R,mid+1,r,nrt<<1|1,k,fg));
		}
		return ans;
	}
}
il int getKth(int L,int R,int k){
	int le=0,ri=1e8,ans=0,mid;
	while(le<=ri){
		mid=(le+ri)>>1;
		if(Seg::qRank(L,R,mid)<=k) ans=mid,le=mid+1;
		else ri=mid-1;
	}
	return ans;
}
int main() {
//	std::ios::sync_with_stdio(0);cin.tie(0);
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; ++i)	scanf("%d",&a[i]);
	Seg::build(1,n,1);
	int op,x,y,z;
	for(int i=1; i<=m; ++i) {
		scanf("%d%d%d",&op,&x,&y);
		if(op==3) Seg::update(1,n,x,y,1),a[x]=y;
		else {
			scanf("%d",&z);
			if(op==1) printf("%d\n",Seg::qRank(x,y,z));
			if(op==2) printf("%d\n",getKth(x,y,z));
			if(op==4) printf("%d\n",Seg::qPre_Back(x,y,1,n,1,z,1));
			if(op==5) printf("%d\n",Seg::qPre_Back(x,y,1,n,1,z,0));
		}
	}
	return 0;
}








 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值