bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

3196: Tyvj 1730 二逼平衡树

Time Limit: 10 Sec  Memory Limit: 128 MB
[Submit][Status][Discuss]

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可能为负数
 
线段树套平衡树
#include<cstdio>
#include<algorithm>
using namespace std;
#define M 3000001
#define N 50001

    int id=0;
    int siz[M],cnt[M],key[M];
    int fa[M],ch[M][2];
    struct TREE
    {
        int root,l,r;
    }tr[N<<2];
    int data[N];
    void Splay_up(int k)
    {
        siz[k]=siz[ch[k][0]]+siz[ch[k][1]]+cnt[k];
    }
    void rotate(int x,int &goal)
    {
        int y=fa[x],z=fa[y];
        int l=ch[y][1]==x,r=l^1;
        if(y==goal) goal=x;
        else ch[z][ch[z][1]==y]=x;
        ch[y][l]=ch[x][r]; ch[x][r]=y; 
        fa[x]=z; fa[y]=x; fa[ch[y][l]]=y;
        Splay_up(y);
    }
    void splay(int x,int &goal)
    {
        int y,z;
        while(x!=goal)
        {
            y=fa[x]; z=fa[y];
            if(y!=goal) 
            {
                if(ch[z][0]==y ^ ch[y][0]==x) rotate(x,goal);
                else rotate(y,goal);
            }
            rotate(x,goal);
            Splay_up(x);
        }
    }
    void Splay_insert(int &rt,int w)
    {    
        if(!rt)
        {
            rt=++id;
            siz[rt]=cnt[rt]=1;
            key[rt]=w;
            return;
        }
        if(key[rt]==w) cnt[rt]++;
        else if(w<key[rt]) Splay_insert(ch[rt][0],w),fa[ch[rt][0]]=rt;
        else Splay_insert(ch[rt][1],w),fa[ch[rt][1]]=rt;
        Splay_up(rt);
    }
    int Splay_getpre(int rt,int x)
    {
        int now=rt,ret;
        while(now)
        {
            if(key[now]>=x) now=ch[now][0];
            else ret=now,now=ch[now][1];
        }
        return ret;
    }
    int Splay_getsuc(int rt,int x)
    {
        int now=rt,ret;
        while(now)
        {
            if(key[now]<=x) now=ch[now][1];
            else ret=now,now=ch[now][0];
        }
        return ret;
    }
    int Splay_number(int now,int w)
    {
        while(1)
        {
            if(key[now]==w) return now;
            if(w<key[now]) now=ch[now][0];
            else now=ch[now][1];
        }
    }
    void del(int & rt,int w)
    {
        int num=Splay_number(rt,w);
        splay(num,rt);
        if(cnt[num]>1) cnt[num]--, siz[num]--;
        else
        {
            int pre=Splay_getpre(rt,w);
            splay(pre,rt);
            ch[pre][1]=ch[num][1];
            fa[ch[pre][1]]=pre;
            Splay_up(pre);
        }
    }
    void add_dummy(int rt,int w,int d)
    {
        ch[rt][d]=++id; siz[rt]++;
        fa[id]=rt; siz[id]=cnt[id]=1; key[id]=w;
    }
    
    void build(int k,int l,int r)
    {
        tr[k].l=l; tr[k].r=r;
        if(l==r) return;
        int mid=l+r>>1;
        build(k<<1,l,mid); 
        build(k<<1|1,mid+1,r);    
    }
    void Segment_insert(int k,int pos,int w)
    {
         Splay_insert(tr[k].root,w);
        if(tr[k].l==tr[k].r) return;
        int mid=tr[k].l+tr[k].r>>1;
        if(pos<=mid) Segment_insert(k<<1,pos,w);
        else Segment_insert(k<<1|1,pos,w);
    }
    void dummy(int k)
    {
        int pre=Splay_getsuc(tr[k].root,-1),suc=Splay_getpre(tr[k].root,1e8);
        splay(pre,tr[k].root);
        add_dummy(pre,-1e8-1,0);
        splay(suc,tr[k].root);
        add_dummy(suc,1e8+1,1);
        if(tr[k].l==tr[k].r) return;
        dummy(k<<1); dummy(k<<1|1);
    }
    int order(int k,int opl,int opr,int w)
    {
        if(tr[k].l>=opl && tr[k].r<=opr)
        {
            int pre=Splay_getpre(tr[k].root,w);
            splay(pre,tr[k].root);
            return siz[ch[pre][0]]+cnt[pre]-1;
        }
        int mid=tr[k].l+tr[k].r>>1,tmp=0;
        if(opl<=mid) tmp+=order(k<<1,opl,opr,w);
        if(opr>mid) tmp+=order(k<<1|1,opl,opr,w);
        return tmp;
    }
    int Segment_number(int l,int r,int w)
    {
        int ll=1,rr=1e8,mid,tmp,ans;
        while(ll<=rr)
        {
            mid=ll+rr>>1;
            tmp=order(1,l,r,mid);
            if(tmp<w) ans=mid,ll=mid+1;
            else rr=mid-1;
        }
        return ans;
    }
    void modify(int k,int pos,int before,int now)
    {
        del(tr[k].root,before);
        Splay_insert(tr[k].root,now);
        if(tr[k].l==tr[k].r)
        {
            data[tr[k].l]=now;
            return;
        }
        int mid=tr[k].l+tr[k].r>>1;
        if(pos<=mid) modify(k<<1,pos,before,now);
        else modify(k<<1|1,pos,before,now);
    }
    int Segment_getpre(int k,int l,int r,int w)
    {
        if(tr[k].l>=l && tr[k].r<=r) return key[Splay_getpre(tr[k].root,w)];
        int mid=tr[k].l+tr[k].r>>1,tmp=-1e8-1;
        if(l<=mid) tmp=max(tmp,Segment_getpre(k<<1,l,r,w));
        if(r>mid) tmp=max(tmp,Segment_getpre(k<<1|1,l,r,w));
        return tmp; 
    }
    int Segment_getsuc(int k,int l,int r,int w)
    {
        if(tr[k].l>=l && tr[k].r<=r) return key[Splay_getsuc(tr[k].root,w)];
        int mid=tr[k].l+tr[k].r>>1,tmp=1e8+1; 
        if(l<=mid) tmp=min(tmp,Segment_getsuc(k<<1,l,r,w));
        if(r>mid) tmp=min(tmp,Segment_getsuc(k<<1|1,l,r,w));
        return tmp;
     }
     
int main()
{
    freopen("psh.in","r",stdin);
    freopen("psh.out","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    build(1,1,n);
    for(int i=1;i<=n;i++) 
    {
        scanf("%d",&data[i]); 
        Segment_insert(1,i,data[i]);
    }
    dummy(1);
    int opt,l,r,k;
    while(m--)
    {
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d%d%d",&l,&r,&k);
            printf("%d
",order(1,l,r,k)+1);
        }
        else if(opt==2)
        {
            scanf("%d%d%d",&l,&r,&k);
            printf("%d
",Segment_number(l,r,k));
        }
        else if(opt==3)
        {
            scanf("%d%d",&l,&k);
            modify(1,l,data[l],k);
        }
        else if(opt==4)
        {
            scanf("%d%d%d",&l,&r,&k);
            printf("%d
",Segment_getpre(1,l,r,k));
        }
        else
        {
            scanf("%d%d%d",&l,&r,&k);
            printf("%d
",Segment_getsuc(1,l,r,k));
        }
    }
}

 

原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7351260.html