二逼平衡树【树套树】

问题描述

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)

输入格式

第一行两个数 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的后继

输出格式

对于操作1,2,4,5各输出一行,表示查询结果

样例输入 1

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

样例输出 1

2
4
3
4
9

样例输入 2

30 10
347297 7767863 4687361 4266761 1869189 6183125 6228737 7377798 2298221 253439 2279737 7603021 9596641 3461977 8857135 7648897 1264321 7381859 2257573 3750694 7066537 7631697 3115165 3367245 3742733 7943233 4901377 2381377 3162917 3567345
1 7 26 2298221
3 19 6712240
4 23 29 3743106
5 7 24 7624712
1 7 22 7066537
5 1 18 251894
2 19 21 1
5 15 16 8855774
2 1 12 10
3 15 3539397

样例输出 2

5
3742733
7631697
9
253439
3750694
8857135
7377798

提示

1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
3.虽然原题没有,但事实上5操作的k可能为负数


题解

这道题很(休闲)烦。。但看题目就知道是树套树
对此主要有两种思考方式。
可以用线段树维护位置,平衡树维护值。
操作一就比较简单,用数棵线段树组成对应区间,直接在平衡树上查找即可。
操作二就乏力了,二分答案操作一
操作三不说。
操作四、五,用数棵线段树组成对应区间,查查前驱后继即可。
此做法的问题在于,操作二可能会带来较高的时间复杂度。

还有一种方法,用线段树维护值,平衡树维护位置
操作二可以变为在线段树上二分值,用平衡树查找对应值域有多少个数在对应区间【l,r】中。
操作一变为查找比x小的数中有多少个在区间【l,r】中。
操作三懒得讲了。
操作四、五,找到在区间【l,r】有数的最小的大于x的值,或最大的小于x的值即可。

为了更快,可离散化

具体见代码。


代码

注:俩树都打得贼烂,有一个会被T掉
1:线段树维护位置,平衡树维护值

#include <cstdio> 
#include <iostream>
#include <cstdlib>
using namespace std; 
const int Q=3000000; 
int f[Q],ls[Q],rs[Q],si[Q],v[Q],cnt[Q],root[Q]; 
void lx(int x) 
{ 
    int y=f[x],z=f[y];
    if(z)if(ls[z]==y)ls[z]=x; 
    else rs[z]=x; 
    f[x]=z; 
    rs[y]=ls[x]; 
    f[rs[y]]=y; 
    ls[x]=y; 
    f[y]=x; 
    si[x]=si[y]; 
    si[y]=si[ls[y]]+si[rs[y]]+cnt[y]; 
} 
void rx(int x) 
{ 
    int y=f[x],z=f[y]; 
    if(z)if(ls[z]==y)ls[z]=x; 
    else rs[z]=x;
    f[x]=z; 
    ls[y]=rs[x]; 
    f[ls[y]]=y; 
    rs[x]=y; 
    f[y]=x; 
    si[x]=si[y]; 
    si[y]=si[ls[y]]+si[rs[y]]+cnt[y]; 
} 
void splay(int x,int be) 
{
    while(f[x])
    {
        int y=f[x],z=f[y]; 
        if(z) 
            if(ls[z]==y) 
                if(ls[y]==x) 
                    rx(y),rx(x); 
                else lx(x),rx(x); 
            else if(rs[y]==x) 
                    lx(y),lx(x); 
                else rx(x),lx(x); 
        else if(ls[y]==x)rx(x); 
            else lx(x); 
    } 
    root[be]=x; 
}
int qian(int x,int be) 
{ 
    splay(x,be); 
    if(!ls[x])return -1; 
    x=ls[x]; 
    while(rs[x])x=rs[x];
    return v[x];
}
int hou(int x,int be) 
{ 
    splay(x,be); 
    if(!rs[x])return -1; 
    x=rs[x]; 
    while(ls[x])x=ls[x];
    return v[x];
} 
void del(int x,int be) 
{ 
    splay(x,be); 
    if((--cnt[x])>0){
        --si[x];
        return;
    }
    int lls=ls[x],rrs=rs[x]; 
    f[lls]=f[rrs]=ls[x]=si[x]=rs[x]=0; 
    if(!lls){
        if(!rrs)root[be]=0;
        else root[be]=rrs;
        return;
    } 
    root[be]=lls; 
    while(rs[lls])lls=rs[lls]; 
    splay(lls,be); 
    rs[lls]=rrs; 
    f[rrs]=lls;
    si[lls]+=si[rrs];
} 
int Find(int y,int be) 
{ 
    int t=root[be]; 
    while(t) 
    { 
        if(v[t]==y){
            if(rand()&1)splay(t,be);return t; 
        }
        if(y<v[t])t=ls[t]; 
        else t=rs[t]; 
    }
    return -1; 
} 
int YWH=0; 
int ins(int y,int be) 
{
    if(!root[be]){
        root[be]=++YWH;
        cnt[YWH]=si[YWH]=1;
        f[YWH]=ls[YWH]=rs[YWH]=0;
        v[YWH]=y;
        return YWH; 
    } 
    int t=root[be]; 
    while(t) 
    { 
        ++si[t]; 
        if(v[t]==y) 
        {++cnt[t];return t;} 
        if(y<v[t]) 
            if(ls[t])t=ls[t]; 
            else{ls[t]=++YWH;f[YWH]=t;break;} 
        else 
            if(rs[t])t=rs[t]; 
            else{rs[t]=++YWH;f[YWH]=t;break;} 
    }
    v[YWH]=y;
    cnt[YWH]=si[YWH]=1;
    ls[YWH]=rs[YWH]=0; 
    splay(YWH,be); 
    return YWH; 
} 
int lef[Q],rig[Q]; 
void add(int now,int l,int r,int x,int v) 
{
    ins(v,now);
    if(l==r)return;
    int mid=l+r >>1;
    if(x<=mid)add(now<<1,l,mid,x,v);
    else add((now<<1)|1,mid+1,r,x,v);
}
void fack(int now,int l,int r,int x,int v) 
{
    del(Find(v,now),now); 
    if(l==r)return; 
    int mid=l+r >>1; 
    if(x<=mid)fack(now<<1,l,mid,x,v); 
    else fack((now<<1)|1,mid+1,r,x,v); 
}
int getrank(int now,int l,int r,int x,int y,int v) 
{
    if(x<=l&&y>=r){ 
        int o=ins(v,now); 
        int p;
        splay(o,now);
        if(!ls[o])p=0; 
        else p=si[ls[o]];
        del(o,now);
        return p; 
    } 
    int temp=0,mid=l+r >>1; 
    if(x<=mid)temp+=getrank(now<<1,l,mid,x,y,v); 
    if(y>mid)temp+=getrank((now<<1)|1,mid+1,r,x,y,v); 
    return temp; 
}
int before(int now,int l,int r,int x,int y,int v) 
{ 
    if(x<=l&&y>=r){ 
        int o=ins(v,now); 
        int p=qian(o,now); 
        del(o,now);
        if(p<0)p=-998244353;
        return p; 
    } 
    int mid=l+r >>1,op=-998244353; 
    if(x<=mid)op=max(op,before(now<<1,l,mid,x,y,v)); 
    if(y>mid)op=max(op,before((now<<1)|1,mid+1,r,x,y,v));
    return op;
} 
int after(int now,int l,int r,int x,int y,int v) 
{
    if(x<=l&&y>=r){
        int o=ins(v,now);
        int p=hou(o,now);
        del(o,now);
        if(p<0)p=998244353;
        return p;
    }
    int mid=l+r >>1,op=998244353; 
    if(x<=mid)op=min(op,after(now<<1,l,mid,x,y,v)); 
    if(y>mid)op=min(op,after((now<<1)|1,mid+1,r,x,y,v));
    return op;
}
int a[50005];
int main()
{

    int i,n,m,x,y,p;
    scanf("%d%d",&n,&m);srand(n^m);
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]),add(1,1,n,i,a[i]); 
    while(m--){
        scanf("%d",&i); 
        switch(i){ 
            case 1:{ 
                scanf("%d%d%d",&x,&y,&p); 
                printf("%d\n",getrank(1,1,n,x,y,p)+1); 
                break;
            }
            case 2:{
                scanf("%d%d%d",&x,&y,&p);
                int L=0,R=100000000;
                while(L<=R){
                    int mid=L+R>>1;
                    if(getrank(1,1,n,x,y,mid)>=p)R=mid-1;
                    else L=mid+1;
                }
                printf("%d\n",R);
                break;
            } 
            case 3:{ 
                scanf("%d%d",&x,&y); 
                fack(1,1,n,x,a[x]); 
                a[x]=y; 
                add(1,1,n,x,a[x]); 
                break; 
            } 
            case 4:{ 
                scanf("%d%d%d",&x,&y,&p); 
                printf("%d\n",before(1,1,n,x,y,p)); 
                break; 
            } 
            case 5:{ 
                scanf("%d%d%d",&x,&y,&p); 
                printf("%d\n",after(1,1,n,x,y,p)); 
                break; 
            } 
        }
    } 
    return 0; 
}

2:线段树维护值,平衡树维护位置

#include <cstdio>  
#include <iostream>
#include <algorithm> 
#include <cstdlib> 
using namespace std;  
const int Q=3000000;  
int f[Q],ls[Q],rs[Q],si[Q],v[Q],cnt[Q],root[Q];  
inline void lx(int x)  
{
    register int y=f[x],z=f[y]; 
    if(z)if(ls[z]==y)ls[z]=x;  
    else rs[z]=x;  
    f[x]=z;  
    rs[y]=ls[x];  
    f[rs[y]]=y;  
    ls[x]=y;  
    f[y]=x;  
    si[x]=si[y];  
    si[y]=si[ls[y]]+si[rs[y]]+cnt[y];  
}
inline void rx(int x)  
{
    register int y=f[x],z=f[y];  
    if(z)if(ls[z]==y)ls[z]=x;  
    else rs[z]=x; 
    f[x]=z;  
    ls[y]=rs[x];  
    f[ls[y]]=y;  
    rs[x]=y;  
    f[y]=x;  
    si[x]=si[y];  
    si[y]=si[ls[y]]+si[rs[y]]+cnt[y];  
}  
void splay(int x,int be)  
{ 
    while(f[x]) 
    { 
        register int y=f[x],z=f[y];  
        if(z)  
            if(ls[z]==y)  
                if(ls[y]==x)  
                    rx(y),rx(x);  
                else lx(x),rx(x);  
            else if(rs[y]==x)  
                    lx(y),lx(x);  
                else rx(x),lx(x);  
        else if(ls[y]==x)rx(x);  
            else lx(x);  
    }  
    root[be]=x;  
}
void del(int x,int be)  
{  
    splay(x,be);  
    if((--cnt[x])>0){ 
        --si[x]; 
        return; 
    }
    int lls=ls[x],rrs=rs[x];  
    f[lls]=f[rrs]=ls[x]=si[x]=rs[x]=0;  
    if(!lls){ 
        if(!rrs)root[be]=0; 
        else root[be]=rrs; 
        return; 
    }  
    root[be]=lls;  
    while(rs[lls])lls=rs[lls];  
    splay(lls,be);  
    rs[lls]=rrs;  
    f[rrs]=lls; 
    si[lls]+=si[rrs]; 
}  
int Find(int y,int be)  
{  
    register int t=root[be];  
    while(t)  
    {  
        if(v[t]==y){
            if(ls[t])
                if(rand()&1)splay(ls[t],be);
            return t;
        }
        if(y<v[t])t=ls[t];  
        else t=rs[t];
    } 
    return -1;  
}  
int YWH=0;  
int ins(int y,int be)  
{
    if(!root[be]){
        root[be]=++YWH; 
        cnt[YWH]=si[YWH]=1;
        v[YWH]=y; 
        return YWH;  
    }  
    int t=root[be];  
    while(t)  
    {  
        ++si[t];  
        if(v[t]==y)  
        {++cnt[t];return t;}  
        if(y<v[t])  
            if(ls[t])t=ls[t];  
            else{ls[t]=++YWH;break;}  
        else  
            if(rs[t])t=rs[t];  
            else{rs[t]=++YWH;break;}  
    }
    f[YWH]=t;
    v[YWH]=y; 
    cnt[YWH]=si[YWH]=1; 
    ls[YWH]=rs[YWH]=0;  
    splay(YWH,be);  
    return YWH;  
}  
int lef[Q],rig[Q],qw=1; 
void add(int now,int l,int r,int x,int v) 
{
    ins(x,now);
    if(l==r)return; 
    int mid=l+r >>1; 
    if(v<=mid){
        if(!lef[now])lef[now]=++qw; 
        add(lef[now],l,mid,x,v);
    }
    else{ 
        if(!rig[now])rig[now]=++qw; 
        add(rig[now],mid+1,r,x,v); 
    } 
} 
void fack(int now,int l,int r,int x,int v) 
{ 
    del(Find(x,now),now);
    if(l==r)return; 
    int mid=l+r >>1; 
    if(v<=mid)
        fack(lef[now],l,mid,x,v); 
    else 
        fack(rig[now],mid+1,r,x,v);
} 
int get(int x,int be) 
{
    if(be==0)return 0;
    int o=ins(x,be);
    splay(o,be); 
    int ans=si[ls[o]]; 
    del(o,be);
    return ans; 
} 
int p1(int now,int l,int r,int x,int y,int v) 
{ 
    if(v>=r)
        return get(y+1,now)-get(x,now); 
    int mid=l+r >>1,temp=0; 
    if(!lef[now])lef[now]=++qw; 
    temp+=p1(lef[now],l,mid,x,y,v); 
    if(v>mid){ 
        if(!rig[now])rig[now]=++qw; 
        temp+=p1(rig[now],mid+1,r,x,y,v); 
    }
    return temp;
} 
int p2(int now,int l,int r,int x,int y,int v) 
{
    if(l==r)return l; 
    int mid=l+r >>1; 
    int be=lef[now],omg=get(y+1,be)-get(x,be);
    if(omg>=v)return p2(lef[now],l,mid,x,y,v); 
    return p2(rig[now],mid+1,r,x,y,v-omg); 
}
int p4(int now,int l,int r,int x,int y,int v) 
{
    if((!now)||l>v||get(y+1,now)-get(x,now)==0)return -11;
    if(l==r)return l;
    int mid=l+r >>1;
    int t=p4(rig[now],mid+1,r,x,y,v);
    if(t>0)return t;
    return p4(lef[now],l,mid,x,y,v);
} 
int p5(int now,int l,int r,int x,int y,int v) 
{ 
    if((!now)||r<v||get(y+1,now)-get(x,now)==0)return 998244353;
    if(l==r)return l;
    int mid=l+r >>1;
    int t=p5(lef[now],l,mid,x,y,v);
    if(t<998244353)return t;
    return p5(rig[now],mid+1,r,x,y,v);
}
int a[50005];
int query[50005][5];
int omg[600000],inc;
int main() 
{  
    int i,n,m,x,y,p; 
    scanf("%d%d",&n,&m);
    srand(n+m-1);
    for(i=1;i<=n;i++) 
        scanf("%d",&a[i]),omg[++inc]=a[i];
    for(i=1;i<=m;i++){
        scanf("%d%d%d",&query[i][0],&query[i][1],&query[i][2]);
        if(query[i][0]!=3)scanf("%d",&query[i][3]);
        if(query[i][0]==1||query[i][0]==4||query[i][0]==5)omg[++inc]=query[i][3];
        else if(query[i][0]==3)omg[++inc]=query[i][2];

    }
    sort(omg+1,omg+inc+1);
    int ofo=unique(omg+1,omg+inc+1)-omg-1;
    for(i=1;i<=n;i++) 
        a[i]=lower_bound(omg+1,omg+ofo+1,a[i])-omg,add(1,1,ofo,i,a[i]);
    for(int j=1;j<=m;j++){ 
        i=query[j][0];
        switch(i){  
            case 1:{
                x=query[j][1];
                y=query[j][2];
                p=query[j][3];
                p=lower_bound(omg+1,omg+ofo+1,p)-omg;
                printf("%d\n",p1(1,1,ofo,x,y,p-1)+1);
                break; 
            } 
            case 2:{ 
                x=query[j][1];
                y=query[j][2];
                p=query[j][3];
                printf("%d\n",omg[p2(1,1,ofo,x,y,p)]);
                break; 
            }  
            case 3:{  
                x=query[j][1];
                y=query[j][2];
                y=lower_bound(omg+1,omg+ofo+1,y)-omg;
                fack(1,1,ofo,x,a[x]);
                a[x]=y;
                add(1,1,ofo,x,a[x]);
                break;
            }
            case 4:{
                x=query[j][1];
                y=query[j][2];
                p=query[j][3];
                p=lower_bound(omg+1,omg+ofo+1,p)-omg;
                printf("%d\n",omg[p4(1,1,ofo,x,y,p-1)]);
                break;
            }
            case 5:{
                x=query[j][1];
                y=query[j][2];
                p=query[j][3];
                p=lower_bound(omg+1,omg+ofo+1,p)-omg;
                printf("%d\n",omg[p5(1,1,ofo,x,y,p+1)]);
                break;  
            }
        }
    }
    return 0;  
}

猜你喜欢

转载自blog.csdn.net/includelhc/article/details/80795664
今日推荐