[树套树] BZOJ3196: 二逼平衡树

本文介绍了一种高效的数据结构实现方法——树套树,利用线段树与平衡树结合解决区间查询问题,包括查询排名、查找指定排名的元素、查询前驱与后继等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

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

题解

求区间第k大,树套树模板题。
外层线段树定序列,内层平衡树询问信息。
询问给定数的区间排名直接做就行了。复杂度O(log22n)
求区间排名为k的值还需要加一层二分答案,用上一问题验证。复杂度O(log32n)
不知道有没有复杂度更低的方法……
还要注意一下常数问题,其他的不必说了。

#include<cstdio>
#include<cstdlib>
const int maxn=50005;
int max(int x,int y){ return x>y?x:y; }
int min(int x,int y){ return x<y?x:y; }
struct node{
    node* ch[2];
    int key,fix,size,cnt;
    node(){}
    node(int w,node* son){ key=w; ch[0]=ch[1]=son; fix=rand(); size=cnt=1; }
    void maintain(){ size=ch[0]->size + ch[1]->size + cnt; }
};
typedef node* P_node;
struct Treap{
    node nil;
    P_node root,null,len;
    Treap(){
        root=null=&nil;
        null->size=null->cnt=0;
        null->ch[0]=null->ch[1]=null;
    }
    void rot(P_node &p,int d){
        P_node k=p->ch[d^1]; p->ch[d^1]=k->ch[d]; k->ch[d]=p;
        p->maintain(); k->maintain(); p=k;
    }
    void _Insert(P_node &p,int tkey){
        if(p==null) p=new node(tkey,null); else
        if(p->key==tkey) p->cnt++; else{
            int d=tkey>p->key;
            _Insert(p->ch[d],tkey); if(p->ch[d]->fix > p->fix) rot(p,d^1);
        }
        p->maintain();
    }
    void _Erase(P_node &p,int tkey){
        if(p==null) return; 
        if(p->key==tkey){
            if(p->cnt>1) p->cnt--; else
            if(p->ch[0]==null||p->ch[1]==null){
                P_node tem=p; p->ch[0]==null?p=p->ch[1]:p=p->ch[0];
                delete tem;
            }else{
                int d=p->ch[0]->fix > p->ch[1]->fix; 
                rot(p,d); _Erase(p->ch[d],tkey);
            }
        } else _Erase(p->ch[tkey>p->key],tkey);
        p->maintain();
    }
    int _Rank(P_node p,int tkey,int res){
        if(p==null) return res+1;
        if(p->key==tkey) return p->ch[0]->size+res+1;
        if(tkey<p->key) return _Rank(p->ch[0],tkey,res);
        return _Rank(p->ch[1],tkey,res+ p->ch[0]->size + p->cnt); 
    }
    int _Pred(P_node p,int tkey){ 
        if(p==null) return -2147483647;
        if(tkey<=p->key) return _Pred(p->ch[0],tkey);
        return max(p->key,_Pred(p->ch[1],tkey));
    } 
    int _Succ(P_node p,int tkey){ 
        if(p==null) return 2147483647;
        if(tkey>=p->key) return _Succ(p->ch[1],tkey);
        return min(p->key,_Succ(p->ch[0],tkey)); 
    }
    void Insert(int tkey){ _Insert(root,tkey); }
    void Erase(int tkey){ _Erase(root,tkey); }
    int Rank(int tkey){ return _Rank(root,tkey,0); }
    int Pred(int tkey){ return _Pred(root,tkey); }
    int Succ(int tkey){ return _Succ(root,tkey); }
};
struct Segment{
    int L,R;
    Segment(){ L=R=-1; } 
    Treap T;
} seg[maxn*4]; 
void Seg_Build(int p,int L,int R){
    seg[p].L=L; seg[p].R=R;
    if(L==R) return;
    int mid=(L+R)>>1;
    Seg_Build(p<<1,L,mid); Seg_Build(p<<1|1,mid+1,R);
}
void Seg_Insert(int p,int pos,int tkey){
    if(p>=4*maxn||seg[p].R<pos||pos<seg[p].L) return;
    if(seg[p].L<=pos&&pos<=seg[p].R) seg[p].T.Insert(tkey); 
    Seg_Insert(p<<1,pos,tkey); Seg_Insert(p<<1|1,pos,tkey);
}
void Seg_Erase(int p,int pos,int tkey){
    if(p>=4*maxn||seg[p].R<pos||pos<seg[p].L) return;
    if(seg[p].L<=pos&&pos<=seg[p].R) seg[p].T.Erase(tkey);
    Seg_Erase(p<<1,pos,tkey); Seg_Erase(p<<1|1,pos,tkey);   
}
int Seg_Rank(int p,int L,int R,int tkey){
    if(p>=4*maxn||seg[p].R<L||R<seg[p].L) return 0;
    if(L<=seg[p].L&&seg[p].R<=R) return seg[p].T.Rank(tkey)-1;
    return Seg_Rank(p<<1,L,R,tkey)+Seg_Rank(p<<1|1,L,R,tkey);
}
int Seg_Kth(int q_L,int q_R,int k){
    int L=0,R=1e+8,res;
    while(L<=R){
        int mid=(L+R)>>1;
        int rk=Seg_Rank(1,q_L,q_R,mid)+1;
        if(rk<=k) L=mid+1, res=mid;
             else R=mid-1; 
    }
    return res;
}
int Seg_Pred(int p,int L,int R,int tkey){
    if(p>=4*maxn||seg[p].R<L||R<seg[p].L) return -2147483647;
    if(L<=seg[p].L&&seg[p].R<=R) return seg[p].T.Pred(tkey);
    return max(Seg_Pred(p<<1,L,R,tkey),Seg_Pred(p<<1|1,L,R,tkey));      
}
int Seg_Succ(int p,int L,int R,int tkey){
    if(p>=4*maxn||seg[p].R<L||R<seg[p].L) return 2147483647;
    if(L<=seg[p].L&&seg[p].R<=R) return seg[p].T.Succ(tkey);
    return min(Seg_Succ(p<<1,L,R,tkey),Seg_Succ(p<<1|1,L,R,tkey));      
}
int getint(){
    char ch=getchar(); int res=0,ff=1;
    while(!('0'<=ch&&ch<='9')){ if(ch=='-') ff=-1; ch=getchar(); }
    while('0'<=ch&&ch<='9') res=res*10+ch-'0', ch=getchar();
    return res*ff;
}
int n,m,a[maxn];
int main(){
    scanf("%d%d",&n,&m);
    Seg_Build(1,1,n);
    for(int i=1;i<=n;i++) Seg_Insert(1,i,a[i]=getint()); 
    while(m--){
        int pd=getint();
        if(pd==1){
            int x=getint(),y=getint(),z=getint();
            printf("%d\n",Seg_Rank(1,x,y,z)+1); 
        } else
        if(pd==2){
            int x=getint(),y=getint(),z=getint();
            printf("%d\n",Seg_Kth(x,y,z));  
        } else
        if(pd==3){
            int x=getint(),y=getint();
            Seg_Erase(1,x,a[x]); Seg_Insert(1,x,y);
            a[x]=y;
        } else
        if(pd==4){
            int x=getint(),y=getint(),z=getint();
            printf("%d\n",Seg_Pred(1,x,y,z));   
        } else     
        if(pd==5){
            int x=getint(),y=getint(),z=getint();
            printf("%d\n",Seg_Succ(1,x,y,z));   
        }
    }
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值