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可能为负数

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);
}