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
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
4
3
4
9
HINT
1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
3.虽然原题没有,但事实上5操作的k可能为负数
Source
本人的第一道线段树套平衡树的题,第一道代码200+的题,这种代码题就是靠实现能力。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#define INF 10000000
using namespace std;
struct treap
{
int l,r,v,size,rnd,w;
}t[5000010];
int n,m,size,ans,root[200010],a[200010],tmp;
inline int Readint();
void update(int k);
void insert(int &k, int x);
void left_turn(int &k);
void right_turn(int &k);
void query_rank(int k,int x);
void query_pre(int k,int l,int r,int x,int y,int num);
void query_nst(int k,int l,int r,int x,int y,int num);
void del(int &k,int x);
void after(int k,int x);
void change(int k,int l,int r,int x,int num,int y);
void get_rank(int k,int l,int r,int x,int y,int num);
void get_index(int x,int y,int z);
void before(int k,int x);
void build(int k,int l,int r,int x,int num);
int main()
{
n = Readint();
m = Readint();
for(int i = 1; i <= n; i ++)
a[i] = Readint(),build(1,1,n,i,a[i]);
for(int i = 1; i <= m; i ++)
{
int c;
c = Readint();
int x,y,k;
switch(c)
{
case 1:x = Readint();y = Readint();k = Readint();tmp = 1;get_rank(1,1,n,x,y,k);printf("%d\n",tmp);break;
case 2:x = Readint();y = Readint();k = Readint();get_index(x,y,k);break;
case 3:x = Readint();y = Readint();change(1,1,n,x,y,a[x]);a[x] = y;break;
case 4:x = Readint();y = Readint();k = Readint();tmp=0;query_pre(1,1,n,x,y,k);printf("%d\n",tmp);break;
case 5:x = Readint();y = Readint();k = Readint();tmp=INF;query_nst(1,1,n,x,y,k);printf("%d\n",tmp);break;
}
}
return 0;
}
inline int Readint()
{
char ch = getchar();
int data = 0,x = 1;
while (ch < '0' || ch > '9')
{
if(ch == '-')x = -1;
ch = getchar();
}
do
{
data = data * 10 + ch - '0';
ch = getchar();
} while (ch >= '0' && ch <= '9');
return data * x;
}
void update(int k)
{
t[k].size = t[ t[k].l ].size + t[ t[k].r ].size + t[k].w;
}
void insert(int &k, int x)
{
if(k == 0)
{
size ++;
k = size;
t[k].size = t[k].w = 1;
t[k].v = x;
t[k].rnd = rand();
return;
}
t[k].size ++;
if(t[k].v == x) t[k].w ++;
else
if(x > t[k].v)
{
insert(t[k].r,x);
if(t[ t[k].r ].rnd < t[k].rnd) left_turn(k);
}
else
{
insert(t[k].l,x);
if(t[ t[k].l ].rnd < t[k].rnd) right_turn(k);
}
}
void right_turn(int &k)
{
int p = t[k].l;
t[k].l = t[p].r;
t[p].r = k;
t[p].size = t[k].size;
update(k);
k = p;
}
void left_turn(int &k)
{
int p = t[k].r;
t[k].r = t[p].l;
t[p].l = k;
t[p].size = t[k].size;
update(k);
k = p;
}
void after(int k,int x)
{
if(k == 0)return;
if(t[k].v > x){tmp = min(t[k].v,tmp); after(t[k].l,x);}
else after(t[k].r,x);
}
void query_rank(int k, int x)
{
if(k == 0) return;
if(t[k].v == x) {tmp += t[ t[k].l ].size;return;}
else if(x > t[k].v) tmp += t[ t[k].l ].size + t[k].w,query_rank(t[k].r,x);
else return query_rank(t[k].l,x);
}
void query_pre(int k,int l,int r,int x,int y,int num)
{
if(l == x && r == y){before(root[k],num);return;}
int mid = (l + r)>>1;
if(mid >= y)query_pre(k<<1,l,mid,x,y,num);
else if(mid<x)query_pre(k<<1|1,mid+1,r,x,y,num);
else
{
query_pre(k<<1,l,mid,x,mid,num);
query_pre(k<<1|1,mid+1,r,mid+1,y,num);
}
}
void query_nst(int k,int l,int r,int x,int y,int num)
{
if(l == x && r == y){after(root[k],num);return;}
int mid = (l + r) >> 1;
if(mid >= y) query_nst(k<<1,l,mid,x,y,num);
else if(mid < x) query_nst(k<<1|1,mid + 1,r,x,y,num);
else
{
query_nst(k<<1,l,mid,x,mid,num);
query_nst(k<<1|1,mid + 1,r,mid + 1,y,num);
}
}
void del(int &k ,int x)
{
if(k == 0) return;
if(t[k].v == x)
{
if(t[k].w > 1)
{
t[k].w --;
t[k].size --;
return;
}
if(t[k].l * t[k].r == 0) k = t[k].l + t[k].r;
else
if(t[ t[k].l ].rnd < t[ t[k].r ].rnd) right_turn(k),del(k,x);
else left_turn(k),del(k,x);
}
else if(t[k].v < x) t[k].size --,del(t[k].r,x);
else t[k].size --, del(t[k].l,x);
}
void change(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)>>1;
if(x <= mid)change(k<<1,l,mid,x,num,y);
else change(k<<1|1,mid+1,r,x,num,y);
}
void get_rank(int k,int l,int r,int x,int y,int num)
{
if(l == x && r == y){query_rank(root[k],num);return;}
int mid=(l + r)>>1;
if(mid >= y)get_rank(k<<1,l,mid,x,y,num);
else if(mid < x)get_rank(k<<1|1,mid + 1,r,x,y,num);
else
{
get_rank(k<<1,l,mid,x,mid,num);
get_rank(k<<1|1,mid+1,r,mid + 1,y,num);
}
}
void get_index(int x,int y,int z)
{
int l = 0,r = INF,ans;
while(l <= r)
{
int mid = (l + r)>>1;
tmp = 1;
get_rank(1,1,n,x,y,mid);
if(tmp <= z)
{
l = mid + 1;
ans = mid;
}
else r = mid - 1;
}
printf("%d\n",ans);
}
void before(int k,int x)
{
if(!k)return;
if(t[k].v < x){tmp = max(t[k].v,tmp);before(t[k].r,x);}
else before(t[k].l,x);
}
void build(int k,int l,int r,int x,int num)
{
insert(root[k],num);
if(l == r) return;
int mid = (l + r)>>1;
if(x <= mid)build(k<<1,l,mid,x,num);
else build(k<<1|1,mid + 1,r,x,num);
}