Bzoj3196 二逼平衡树

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

额,这个题,看了一眼就知道是线段树套线段树啦,所以随手糊一发

#pragma GCC opitmize("O3")
#pragma G++ opitmize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 50010
#define gR 0,10000000,c[x].rt
using namespace std;
int t=0,n,m,v[50010];
struct dn{ int l,r,s; dn(){l=r=s=0;} } s[11000010];
struct Segment{
	int rt; Segment(){ rt=0; }
	void insert(int l,int r,int& x,int k){
		if(!x) x=++t;
		if(l==r){ ++s[x].s; return; }
		int m=l+r>>1;++s[x].s;
		if(k<=m) insert(l,m,s[x].l,k);
		  else insert(m+1,r,s[x].r,k);
	}
	void remove(int l,int r,int& x,int k){
		if(l==r){ --s[x].s; return; }
		int m=l+r>>1; --s[x].s;
		if(k<=m) remove(l,m,s[x].l,k);
		  else remove(m+1,r,s[x].r,k);
	}
	int gMax(int l,int r,int x){
		if(l==r) return l;
		int m=l+r>>1;
		if(s[s[x].r].s) return gMax(m+1,r,s[x].r);
		else return gMax(l,m,s[x].l);
	}
	int gMin(int l,int r,int x){
		if(l==r) return l;
		int m=l+r>>1;
		if(s[s[x].l].s) return gMin(l,m,s[x].l);
		else return gMin(m+1,r,s[x].r);
	}
	int gRank(int l,int r,int x,int k){
		if(l==r) return 0;
		int m=l+r>>1;
		if(k<=m) return gRank(l,m,s[x].l,k);
		else return s[s[x].l].s+gRank(m+1,r,s[x].r,k);
	}
	int	gPre(int l,int r,int x,int k){
		if(l==r) return k;
		int m=l+r>>1;
		if(k<=m) return gPre(l,m,s[x].l,k);
		else {
			int p=gPre(m+1,r,s[x].r,k);
			if(p==k && s[s[x].l].s) return gMax(l,m,s[x].l);
			else return p;
		}
	}
	int gSuc(int l,int r,int x,int k){
		if(l==r) return k;
		int m=l+r>>1;
		if(m<k) return gSuc(m+1,r,s[x].r,k);
		else {
			int p=gSuc(l,m,s[x].l,k);
			if(p==k && s[s[x].r].s) return gMin(m+1,r,s[x].r);
			else return p;
		}
	}
} c[200010];
void modify(int l,int r,int x,int p,int k){
	c[x].remove(gR,v[p]); c[x].insert(gR,k);
	if(l==r) return;
	int m=l+r>>1;
	if(p<=m) modify(l,m,x<<1,p,k);
	else modify(m+1,r,x<<1|1,p,k);
}
int getrank(int l,int r,int x,int L,int R,int k){
	if(L<=l && r<=R) return c[x].gRank(gR,k);
	int m=l+r>>1,S=0;
	if(L<=m) S+=getrank(l,m,x<<1,L,R,k);
	if(m<R) S+=getrank(m+1,r,x<<1|1,L,R,k);
	return S;
}
int getpre(int l,int r,int x,int L,int R,int k){
	if(L<=l && r<=R){
		int p=c[x].gPre(gR,k);
		return p==k?-1<<30:p;
	}
	int m=l+r>>1,S=-1<<30;
	if(L<=m) S=max(S,getpre(l,m,x<<1,L,R,k));
	if(m<R) S=max(S,getpre(m+1,r,x<<1|1,L,R,k));
	return S;
}
int getsuc(int l,int r,int x,int L,int R,int k){
	if(L<=l && r<=R){
		int p=c[x].gSuc(gR,k);
		return p==k?1<<30:p;
	}
	int m=l+r>>1,S=1<<30;
	if(L<=m) S=min(S,getsuc(l,m,x<<1,L,R,k));
	if(m<R) S=min(S,getsuc(m+1,r,x<<1|1,L,R,k));
	return S;
}
int gKth(int l,int r,int k){
	int L=0,R=1e8;
	for(int m;L<R;){
		m=L+R+1>>1;
		if(getrank(1,n,1,l,r,m)+1<=k) L=m;
		else R=m-1;
	}
	return L;
}
void build(int l,int r,int x){
	for(int i=l;i<=r;++i) c[x].insert(gR,v[i]);
	if(l==r) return;
	int m=l+r>>1;
	build(l,m,x<<1);
	build(m+1,r,x<<1|1);
}
int main(){
	freopen("1.in","r",stdin);
	freopen("1.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i) scanf("%d",v+i);
	build(1,n,1);
	for(int o,a,b,c;m--;){
		scanf("%d%d%d",&o,&a,&b);
		if(o^3) scanf("%d",&c);
		if(o==1) printf("%d
",getrank(1,n,1,a,b,c)+1);
		else if(o==2) printf("%d
",gKth(a,b,c));
		else if(o==3) modify(1,n,1,a,b),v[a]=b;
		else if(o==4) printf("%d
",getpre(1,n,1,a,b,c));
		else if(o==5) printf("%d
",getsuc(1,n,1,a,b,c));
	}
}
无比优美,结果re了,跑到tyvj上面搞个数据发现空间被卡了。。。。

正解是线段树套(treap,splay,替罪羊。。。)

原文地址:https://www.cnblogs.com/Extended-Ash/p/9477306.html