BZOJ3196 二逼平衡树

12 篇文章 0 订阅
12 篇文章 0 订阅

Description

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询 x在区间内的排名;
2.查询区间内排名为 k 的值;
3.修改某一位置上的数值;
4.查询 x 在区间内的前趋(前趋定义为小于 x,且最大的数);
5.查询 x 在区间内的后继(后继定义为大于 x,且最小的数)。

Input

第一行两个数 n,m,表示长度为 n 的有序序列和 m 个操作。
第二行有 n个数,表示有序序列。
下面有 m 行,每行第一个数表示操作类型:
1.之后有三个数 l,r,x表示查询 x在区间 [l,r] 的排名;
2.之后有三个数 l,r,k表示查询区间 [l,r]内排名为 k的数;
3.之后有两个数 pos,x表示将 pos位置的数修改为 x;
4.之后有三个数 l,r,x表示查询区间 [l,r]内 x 的前趋;
5.之后有三个数 l,r,x表示查询区间 [l,r]内 x 的后继。

Output

对于操作 1,2,4,5各输出一行,表示查询结果。

Sample Input

9 6

4 2 2 1 9 4 0 1 1

2 1 4 3

3 4 10

2 1 4 3

1 2 5 9

4 3 9 5

5 2 8 5

Sample Output

2

4

3

 4

9

Hint

1≤n,m≤5×10​^4​​ ,−10​^8​​ ≤k,x≤10^​8

树套树的模板题,调了lz4天= =各种错误都写出来了,我也不知道该说什么好。

#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;}
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
const int N = 5e4+10,Maxsiz = N*log2(N)*2;
int n,m,a[N];
struct Splay{
	int p[Maxsiz],ch[Maxsiz][2];
	int ct,vl[Maxsiz],siz[Maxsiz],cnt[Maxsiz];
	#define Ls(x) ch[x][0]
	#define rs(x) ch[x][1]
	#define maintain(x) siz[x]=siz[Ls(x)]+siz[rs(x)]+cnt[x]
	inline void rotate(int x){
		int f=p[x],gf=p[f],tp=rs(f)==x,son=ch[x][!tp];
		ch[p[son]=f][tp]=son,maintain(f);
		ch[p[f]=x][!tp]=f,maintain(x);
		ch[p[x]=gf][rs(gf)==f]=x;
	}
	inline void splay(int x,int goal,int &root){
		if(x==goal)return ;
		while(p[x]^goal){
			if((p[p[x]]^goal)&&((rs(p[p[x]])==p[x])==(rs(p[x])==x)))rotate(p[x]);
			rotate(x);
		}
		if(!goal)root=x;
	}
	inline void newnode(int x,int k,int Fa){
		siz[x]=cnt[x]=1;vl[x]=k;p[x]=Fa;
	}
	inline void insert(int &x,int k,int Fa,int &root){
		if(vl[x]==k)return ++cnt[x],splay(x,0,root),void();
		if(!x)return newnode(x=++ct,k,Fa),splay(x,0,root),void();
		insert(ch[x][vl[x]<k],k,x,root);
	}
	inline int findpre(int x){
		for(x=Ls(x);rs(x);x=rs(x));
		return x;
	}
	inline int findsub(int x){
		for(x=rs(x);Ls(x);x=Ls(x));
		return x;
	}
	inline void delet(int k,int &root){
		int x;for(x=root;vl[x]^k;vl[x]>k?x=Ls(x):x=rs(x));
		--cnt[x],splay(x,0,root);
		if(cnt[x]>=1)return ;
		int pre=findpre(x),sub=findsub(x);
		splay(pre,0,root),splay(sub,root,root);
		Ls(sub)=0,maintain(sub),maintain(pre);
	}
	inline int getrank(int x,int k){
		int tot=0;
		while(x)vl[x]<k?tot+=siz[Ls(x)]+cnt[x],x=rs(x):x=Ls(x);
		return tot-1;
	}
	inline int getpre(int x,int k){
		int ans=-(1<<30);
		for(;x;vl[x]>=k?x=Ls(x):x=rs(x))if(vl[x]<k&&vl[x]>ans)ans=vl[x];
		return ans;
	}
	inline int getsub(int x,int k){
		int ans=(1<<30);
		for(;x;vl[x]<=k?x=rs(x):x=Ls(x))if(vl[x]>k&&vl[x]<ans)ans=vl[x];
		return ans;
	}
}sp;
struct SegMent{
	struct tree{
		int L,r,rt;
	}t[N<<2];
	#define Lc v<<1
	#define rc v<<1|1
	inline int getsub(int v,int A,int b,int k){
		if(t[v].L>b||t[v].r<A)return (1<<30);
		if(A<=t[v].L&&t[v].r<=b)return sp.getsub(t[v].rt,k);
		return min(getsub(Lc,A,b,k),getsub(rc,A,b,k));
	}
	inline int getpre(int v,int A,int b,int k){
		if(t[v].L>b||t[v].r<A)return -(1<<30);
		if(A<=t[v].L&&t[v].r<=b)return sp.getpre(t[v].rt,k);
		return max(getpre(Lc,A,b,k),getpre(rc,A,b,k));
	}
	inline void modify(int v,int A,int b,int k,int cmd){
		if(t[v].L>b||t[v].r<A)return ;
		~cmd?sp.insert(t[v].rt,k,0,t[v].rt):sp.delet(k,t[v].rt);
		if(A<=t[v].L&&t[v].r<=b)return ;
		modify(Lc,A,b,k,cmd),modify(rc,A,b,k,cmd);
	}
	inline int getrank(int v,int A,int b,int k){
		if(t[v].L>b||t[v].r<A)return 0;
		if(A<=t[v].L&&t[v].r<=b)return sp.getrank(t[v].rt,k);
		return getrank(Lc,A,b,k)+getrank(rc,A,b,k);
	}
	inline void build(int v,int L,int r){
		int Mid=L+r>>1;
		t[v]=(tree){L,r,0};
		sp.insert(t[v].rt,-(1<<30),0,t[v].rt);
		Inc(i,L,r)sp.insert(t[v].rt,a[i],0,t[v].rt);
		sp.insert(t[v].rt,(1<<30),0,t[v].rt);
		if(L==r)return ;
		build(Lc,L,Mid),build(rc,Mid+1,r);
	}
}tr;
inline void init(){
	n=Getint(),m=Getint();
	Inc(i,1,n)a[i]=Getint();
}
inline int getrank(int L,int r,int k){
	return tr.getrank(1,L,r,k)+1;
}
inline int getkth(int A,int b,int kth){
	int ans;for(int x=tr.t[1].rt;x;){
		if(tr.getrank(1,A,b,sp.vl[x])<kth)ans=sp.vl[x],x=sp.rs(x);
		else x=sp.Ls(x);
	}
	return ans;
}
inline void modify(){
	int x=Getint(),k=Getint();
	tr.modify(1,x,x,a[x],-1);
	a[x]=k;
	tr.modify(1,x,x,a[x],1);
}
inline void solv(){
	memset(sp.vl,63,sizeof(sp.vl));
	tr.build(1,1,n);
	Inc(i,1,m){
		int op=Getint(),L,r,k;
		if(op^3)L=Getint(),r=Getint(),k=Getint();
		if(op==1)cout<<getrank(L,r,k)<<"\n";
		if(op==2)cout<<getkth(L,r,k)<<"\n";
		if(op==3)modify();
		if(op==4)cout<<tr.getpre(1,L,r,k)<<"\n";
		if(op==5)cout<<tr.getsub(1,L,r,k)<<"\n";
	}
}
int main(){
//	freopen("erbi.in","r",stdin);
//	freopen("erbi.out","w",stdout);
	init();
	solv();
	return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值