Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)
Input
第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继
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的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
3.虽然原题没有,但事实上5操作的k可能为负数
解法:树套树SB题
//二逼平衡树 #include <bits/stdc++.h> using namespace std; const int maxn = 200010; const int maxm = 3000010; const int inf = 1e8; int n, m, sz, tmp, a[maxn]; int ls[maxm], rs[maxm], rnd[maxm], v[maxm], s[maxm], w[maxm]; int root[maxn]; void update(int k){ s[k]=s[ls[k]]+s[rs[k]]+w[k]; } void rturn(int &k){ int t=ls[k]; ls[k]=rs[t]; rs[t]=k; s[t]=s[k]; update(k); k=t; } void lturn(int &k){ int t=rs[k]; rs[k]=ls[t]; ls[t]=k; s[t]=s[k]; update(k); k=t; } void insert(int &k, int x){ if(k==0){ sz++; k=sz; s[k]=w[k]=1; v[k]=x; rnd[k]=rand(); return; } s[k]++; if(v[k]==x) w[k]++; else if(x>v[k]){ insert(rs[k],x); if(rnd[rs[k]]<rnd[k]) lturn(k); } else{ insert(ls[k],x); if(rnd[ls[k]]<rnd[k]) rturn(k); } } void del(int &k, int x){ if(v[k] == x){ if(w[k]>1){ w[k]--; s[k]--; return; } if(ls[k]*rs[k]==0) k=ls[k]+rs[k]; else if(rnd[ls[k]]<rnd[rs[k]]){ rturn(k); del(k,x); } else{ lturn(k); del(k,x); } } else if(x>v[k]){ del(rs[k],x); s[k]--; } else{ del(ls[k],x); s[k]--; } } void build(int k, int l, int r, int x, int num){ insert(root[k], num); if(l == r) return; int mid = (l+r)/2; if(x<=mid) build(k<<1,l,mid,x,num); else build(k<<1|1,mid+1,r,x,num); } void query_rank(int k, int x){ if(k == 0) return; if(v[k] == x) {tmp += s[ls[k]]; return;} else if(x>v[k]){ tmp += s[ls[k]]+w[k]; query_rank(rs[k],x); } else{ query_rank(ls[k], x); } } void query_rank(int k, int l, int r, int x, int y, int num){ if(l==x&&y==r){ query_rank(root[k], num); return; } int mid=(l+r)/2; if(y<=mid) query_rank(k<<1,l,mid,x,y,num); else if(x>mid) query_rank(k<<1|1,mid+1,r,x,y,num); else{ query_rank(k<<1,l,mid,x,mid,num); query_rank(k<<1|1,mid+1,r,mid+1,y,num); } } void getid(int x, int y, int z){ int l=0,r=inf,ans; while(l<=r){ int mid=(l+r)/2; tmp=1; query_rank(1,1,n,x,y,mid); if(tmp<=z){ ans=mid; l=mid+1; } else{ r=mid-1; } } printf("%d\n", ans); } void del(int k, int l, int r, int x, int num, int y){ del(root[k], y); insert(root[k], num); if(l == r) return; int mid=(l+r)/2; if(x<=mid) del(k<<1,l,mid,x,num,y); else del(k<<1|1,mid+1,r,x,num,y); } void query_pro(int k, int x){ if(!k) return; if(v[k]<x){tmp=max(v[k],tmp);query_pro(rs[k],x);} else query_pro(ls[k],x); } void query_sub(int k, int x){ if(!k) return; if(v[k]>x){tmp=min(tmp,v[k]); query_sub(ls[k],x);} else query_sub(rs[k],x); } void query_pro(int k, int l, int r, int x, int y, int num){ if(l==x&&y==r){ query_pro(root[k], num); return; } int mid=(l+r)/2; if(y<=mid) query_pro(k<<1,l,mid,x,y,num); else if(x>mid) query_pro(k<<1|1,mid+1,r,x,y,num); else{ query_pro(k<<1,l,mid,x,mid,num); query_pro(k<<1|1,mid+1,r,mid+1,y,num); } } void query_sub(int k, int l, int r, int x, int y, int num){ if(l==x&&y==r){ query_sub(root[k], num); return; } int mid=(l+r)/2; if(y<=mid) query_sub(k<<1,l,mid,x,y,num); else if(x>mid) query_sub(k<<1|1,mid+1,r,x,y,num); else{ query_sub(k<<1,l,mid,x,mid,num); query_sub(k<<1|1,mid+1,r,mid+1,y,num); } } int main() { scanf("%d %d", &n,&m); for(int i=1; i<=n; i++) scanf("%d", &a[i]); for(int i=1; i<=n; i++) build(1,1,n,i,a[i]); for(int i=1; i<=m; i++){ int op,x,y,k; scanf("%d",&op); if(op==1){ scanf("%d %d %d",&x,&y,&k); tmp=1; query_rank(1,1,n,x,y,k); printf("%d\n", tmp); } else if(op == 2){ scanf("%d %d %d", &x,&y,&k); getid(x,y,k); } else if(op == 3){ scanf("%d %d", &x,&y); del(1,1,n,x,y,a[x]); a[x]=y; } else if(op == 4){ scanf("%d %d %d", &x,&y,&k); tmp = 0; query_pro(1,1,n,x,y,k); printf("%d\n", tmp); } else{ scanf("%d %d %d", &x,&y,&k); tmp = inf; query_sub(1,1,n,x,y,k); printf("%d\n", tmp); } } return 0; }