首页 > 代码库 > [bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)

[bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)

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 64 2 2 1 9 4 0 1 12 1 4 33 4 102 1 4 31 2 5 94 3 9 55 2 8 5

Sample Output

24349

HINT

1.n和m的数据范围:n,m<=50000

 

2.序列中每个数的数据范围:[0,1e8]

 

3.虽然原题没有,但事实上5操作的k可能为负数

Solution

 

#include <stdio.h>#include <stdlib.h>#define N 50010#define inf 0x7fffffff#define opp 0x80000000#define mid ((x>>1)+(y>>1)+(x&y&1))#define dmax(x,y) ((x)>(y)?(x):(y))#define dmin(x,y) ((x)<(y)?(x):(y))#define RG register#define inline __inline__ __attribute__((always_inline))inline int Rin(){    RG int x=0,c=getchar(),f=1;    for(;c<48||c>57;c=getchar())        if(!(c^45))f=-1;    for(;c>47&&c<58;c=getchar())        x=(x<<1)+(x<<3)+c-48;    return x*f;}int n,m,a[N];namespace Seg{    struct Treap{        struct Nt{            Nt*ch[2];            int s,w,v,r;            Nt(RG int v,RG Nt*_) : v(v),r(rand()) {                s=w=1;                ch[0]=ch[1]=_;            }            inline void maintain(){                s=w+ch[0]->s+ch[1]->s;            }        }*root,*null;        Treap(){            null=new Nt(0,0x0);            null->s=null->w=0;            null->r=inf;            null->ch[0]=null->ch[1]=null;            root=null;        }        void rotate(RG Nt*&o,RG int d){            Nt*k=o->ch[1^d];            o->ch[1^d]=k->ch[d];            k->ch[d]=o;            o->maintain();            k->maintain();            o=k;        }        void insert(RG Nt*&o,RG int v){            if(o==null){                o=new Nt(v,null);                return;            }            o->s++;            if(v==o->v)                o->w++;            else{                RG int d=v > o->v;                insert(o->ch[d],v);                if(o->ch[d]->r < o->r)                    rotate(o,1^d);            }        }        void remove(RG Nt*&o,RG int v){            if(o==null)                return;            if(o->v==v){                if(o->w>1){                    o->s--;                    o->w--;                    return;                }                if(o->ch[0]!=null && o->ch[1]!=null){                    RG int d=o->ch[0]->r > o->ch[1]->r;                    rotate(o,d);                    remove(o->ch[d],v);                }                else o=o->ch[o->ch[0]==null];            }            else{                o->s--;                remove(o->ch[o->v < v],v);            }            if(o!=null)                o->maintain();        }        inline int pre(RG int v){            RG int ans=opp;            for(RG Nt*o=root;o!=null;)                v > o->v ? (ans=dmax(ans,o->v),o=o->ch[1]) : o=o->ch[0];            return ans;        }        inline int nxt(RG int v){            RG int ans=inf;            for(RG Nt*o=root;o!=null;)                v < o->v ? (ans=dmin(ans,o->v),o=o->ch[0]) : o=o->ch[1];            return ans;        }        inline int rank(RG int v){            RG int ans=0;            for(Nt*o=root;o!=null;){                RG int d= v==o->v? -1 : (o->v < v);                if(d==-1){                    ans+=o->ch[0]->s;                    break;                }                d?(ans+=o->ch[0]->s+o->w,o=o->ch[1]):o=o->ch[0];            }            return ans;        }    }rt[N<<2];    void build(RG int x,RG int y,RG int k){        for(RG int i=x;i<=y;i++)            rt[k].insert(rt[k].root,a[i]);        if(x<y){            build(x,mid,k<<1);            build(mid+1,y,k<<1|1);        }    }    void modify(RG int x,RG int y,RG int k,RG int pos,RG int num){        rt[k].remove(rt[k].root,a[pos]);        rt[k].insert(rt[k].root,num);        if(x<y)            pos<=mid ? modify(x,mid,k<<1,pos,num):                modify(mid+1,y,k<<1|1,pos,num);    }    int getrank(RG int x,RG int y,RG int k,RG int l,RG int r,RG int num){        if(x==l && y==r)            return rt[k].rank(num);        if(r<=mid)            return getrank(x,mid,k<<1,l,r,num);        if(l>mid)            return getrank(mid+1,y,k<<1|1,l,r,num);        return getrank(x,mid,k<<1,l,mid,num)+getrank(mid+1,y,k<<1|1,mid+1,r,num);    }    int getpre(RG int x,RG int y,RG int k,RG int l,RG int r,RG int num){        if(x==l && y==r)            return rt[k].pre(num);        if(r<=mid)            return getpre(x,mid,k<<1,l,r,num);        if(l>mid)            return getpre(mid+1,y,k<<1|1,l,r,num);        return dmax(getpre(x,mid,k<<1,l,mid,num),getpre(mid+1,y,k<<1|1,mid+1,r,num));    }    int getnxt(RG int x,RG int y,RG int k,RG int l,RG int r,RG int num){        if(x==l && y==r)            return rt[k].nxt(num);        if(r<=mid)            return getnxt(x,mid,k<<1,l,r,num);        if(l>mid)            return getnxt(mid+1,y,k<<1|1,l,r,num);        return dmin(getnxt(x,mid,k<<1,l,mid,num),getnxt(mid+1,y,k<<1|1,mid+1,r,num));    }    inline int getkth(RG int l,RG int r,RG int k){        RG int x=0,y=1e8;        while(x<=y)            getrank(1,n,1,l,r,mid) < k ?                x=mid+1:                y=mid-1;        if(getrank(1,n,1,l,r,x)>=k)            x=getpre(1,n,1,l,r,x);        return x;    }}int main(){    srand(K+a+i+b+a);    n=Rin(),m=Rin();    for(int i=1;i<=n;i++)        a[i]=Rin();    Seg::build(1,n,1);    while(m--){        RG int x,y,k,c=Rin();        switch(c){            case 1 :                x=Rin(),y=Rin(),k=Rin();                printf("%d\n",Seg::getrank(1,n,1,x,y,k)+1);                break;            case 2 :                x=Rin(),y=Rin(),k=Rin();                printf("%d\n",Seg::getkth(x,y,k));                break;            case 3 :                x=Rin(),k=Rin();                Seg::modify(1,n,1,x,k);                a[x]=k;                break;            case 4 :                x=Rin(),y=Rin(),k=Rin();                printf("%d\n",Seg::getpre(1,n,1,x,y,k));                break;            case 5 :                x=Rin(),y=Rin(),k=Rin();                printf("%d\n",Seg::getnxt(1,n,1,x,y,k));                break;            default : break;        }    }    return 0;}

 

[bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)