[P3380](树套树板子)

维护一段区间内的排名,第k小,前驱,后继

线段树套平衡树即可

线段树上的每一个节点都建一棵平衡树维护所在的这一区间

修改和查前驱和后继就在线段树上对相应的区间进行操作即可 \(O(log^2)\)

查排名就查找每一小段区间内此数的排名求和,查询每一区间小于此数的个数,最后求和加上1(它本身)即可也能在 \(O(log^2)\) 求解

求第k小在线段树上操作不了,考虑二分答案,找排名小于等于k的数中最大的那一个 复杂度大约是 \(O(log^3)\) 的数量级

code
#include<bits/stdc++.h>
//================================================
//#define LOCAL FLANDRE KAWAII 
#ifndef LOCAL
    constexpr int SIZE(1<<20);
    char in[SIZE],out[SIZE],*p1=in,*p2=in,*p3=out;
    #define getchar() (p1==p2&&(p2=(p1=in)+fread(in,1,SIZE,stdin),p1==p2)?EOF:*p1++)
    #define flush() (fwrite(out,1,p3-out,stdout))
    #define putchar(x) (p3==out+SIZE&&(flush(),p3=out),*p3++=(x))
    class Flush{public:~Flush(){flush();}}_;
#endif
inline int read(){
	int x(0);bool f(0);char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar()) f^=ch=='-';
	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
	return f?x=-x:x;
}
inline void write(int x,char ch){
	x<0?x=-x,putchar('-'):0;static short Sta[50],top(0);
	do{Sta[++top]=x%10;x/=10;}while(x);
	while(top) putchar(Sta[top--]|48);
	putchar(ch);
}
//===================================================
constexpr int N(50005),INF(0x7fffffff);
int n,m;
int a[N],b[N];
int siz[N*30],ch[N*30][2],fa[N*30],cnt[N*30],val[N*30],tot;
namespace Splay{
	inline void upd(int x){siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+cnt[x];}
	inline bool chk(int x){return x==ch[fa[x]][1];}
	inline void rotate(int x){
		int f=fa[x],k=chk(x),ff=fa[f],kk=chk(f);
		fa[ch[f][k]=ch[x][k^1]]=f;
		fa[ch[x][k^1]=f]=x;
		fa[x]=ff;if(ff) ch[ff][kk]=x;
		upd(f);upd(x);
	}
	inline void splay(int &rt,int x,int goal=0){
		for(int f=fa[x];f!=goal;rotate(x),f=fa[x])
			if(fa[f]!=goal) rotate(chk(x)==chk(f)?f:x);
		if(!goal) rt=x;
	}
	inline void find(int &rt,int x){
		int now=rt;if(!now) return;
		while(ch[now][x>val[now]]&&x!=val[now]) now=ch[now][x>val[now]];
		splay(rt,now);
	}
	inline void ins(int &rt,int x){
    	int now=rt,f(0);
    	while(now&&val[now]!=x){f=now;now=ch[now][x>val[now]];}
    	if(now){cnt[now]++;siz[now]++;}
    	else{
			now=++tot;val[tot]=x;cnt[tot]=siz[tot]=1;
       		fa[tot]=f;if(f) ch[f][x>val[f]]=tot;
    	}
    	splay(rt,now);
	}
	inline int Kth(int &rt,int k){
		int now=rt;
		while(1){
			if(ch[now][0]&&k<=siz[ch[now][0]]) now=ch[now][0];
			else if(k>siz[ch[now][0]]+cnt[now]){k-=siz[ch[now][0]]+cnt[now];now=ch[now][1];} 
			else return splay(rt,now),now;
		}
	}
	inline int Rank(int &rt,int x){find(rt,x);int ans=siz[ch[rt][0]];if(val[rt]<x)ans+=cnt[rt];return ans;}
	inline int Pre(int &rt,int x){
		find(rt,x);if(val[rt]<x) return rt;
		int now=ch[rt][0];
		while(ch[now][1]) now=ch[now][1];
		return splay(rt,now),now;
	}
	inline int Nxt(int &rt,int x){
		find(rt,x);if(val[rt]>x) return rt;
		int now=ch[rt][1];
		while(ch[now][0]) now=ch[now][0];
		return splay(rt,now),now;
	}
	inline void modify(int &rt,int x,int val){
		int last=Pre(rt,x),next=Nxt(rt,x);
		splay(rt,last);splay(rt,next,last);
		int now=ch[next][0];
		if(cnt[now]>1){cnt[now]--;siz[now]--;splay(rt,now);}
		else ch[next][0]=0;
		upd(next),upd(last);ins(rt,val);
	}
}
namespace SMT{
	#define ls rt<<1
	#define rs rt<<1|1
	int L[N<<2],R[N<<2],root[N<<2];
	void build(int rt,int l,int r){
		L[rt]=l;R[rt]=r;	
		Splay::ins(root[rt],-INF);Splay::ins(root[rt],INF);
		for(int i=l;i<=r;++i) Splay::ins(root[rt],a[i]);
		if(l==r) return; 
	    int mid=l+r>>1;build(ls,l,mid);build(rs,mid+1,r);
	}
	void modify(int rt,int x,int val){
		Splay::modify(root[rt],a[x],val);
		if(L[rt]==R[rt]) return;
		int mid=L[rt]+R[rt]>>1;
		if(x<=mid) modify(ls,x,val);
		else modify(rs,x,val);
	}
	int Qpre(int rt,int l,int r,int x){
		if(R[rt]<l||L[rt]>r) return -INF;
		if(L[rt]>=l&&R[rt]<=r) return val[Splay::Pre(root[rt],x)];
		return std::max(Qpre(ls,l,r,x),Qpre(rs,l,r,x));
	}
	int Qnxt(int rt,int l,int r,int x){
		if(R[rt]<l||L[rt]>r) return INF;
		if(L[rt]>=l&&R[rt]<=r) return val[Splay::Nxt(root[rt],x)];
		return std::min(Qnxt(ls,l,r,x),Qnxt(rs,l,r,x));
	}
	int Qrank(int rt,int l,int r,int x){
		if(R[rt]<l||L[rt]>r) return 0;
		if(L[rt]>=l&&R[rt]<=r) return Splay::Rank(root[rt],x)-1;
		return Qrank(ls,l,r,x)+Qrank(rs,l,r,x);
	}
}
int main(){
	n=read();m=read();
	for(int i=1;i<=n;++i){a[i]=read();}
	SMT::build(1,1,n);
	for(int i=1,opt,x,y,z,l,r;i<=m;++i){
		opt=read();x=read();y=read();
		switch(opt){
			case 1:z=read();/*std::cout<<"1: ";*/write(SMT::Qrank(1,x,y,z)+1,'\n');break;
			case 2:z=read();/*std::cout<<"2: ";*/
				   l=0,r=100000000; 
				   while(l<r){
				   		int mid=l+r+1>>1;
				   		if(SMT::Qrank(1,x,y,mid)+1<=z) l=mid;
				   		else r=mid-1;
				   }
				   write(l,'\n');break;
			case 3:SMT::modify(1,x,y);a[x]=y;break;
			case 4:z=read();/*std::cout<<"4: ";*/write(SMT::Qpre(1,x,y,z),'\n');break;
			case 5:z=read();/*std::cout<<"5: ";*/write(SMT::Qnxt(1,x,y,z),'\n');break;
		}
	}
	return 0;
}
posted @ 2023-05-31 16:42  Flandreqwq  阅读(18)  评论(0编辑  收藏  举报