Loading

树套树

[例题](【模板】二逼平衡树(树套树) - 洛谷)

我们首先分析一下,如果要查询前驱后继,我们就需要用到平衡树,但是平衡树储存不了区间信息,所以我们用线段树套平衡树,即线段树的每一个节点都是一个平衡树,

考虑如何实现以下操作:

  • 求区间查询排名。

  • 求区间查询某个排名的数。

  • 把某个位置的数改成某个数。

  • 查询一个区间内 \(k\) 的前驱。

  • 查询一个区间内 \(k\) 的后继。

首先考虑我们可以在一个平衡树内查询小于一个数的数的个数,由此来得到某个数的排名。

然后对于查询数,我们可以通过二分,这样时间复杂度就是两个 \(\log\)

代码里实现用的是 FHQTreap,因为常数原因,需要开 O2 才能过。

代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 1000100
#define M 50010
using namespace std;

const int INF=2147483647;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

template<typename T> inline T Min(T a,T b){return a<b?a:b;}
template<typename T> inline T Max(T a,T b){return a<b?b:a;}

struct Node{
        int val,size,ls,rs,key;
        inline Node(){}
        inline Node(int val,int size,int ls,int rs,int key) : val(val),size(size),ls(ls),rs(rs),key(key) {}
}p[N];

int tot,a[N],n,m;
int Stack[N],top;

inline int random(int n){return 1ll*rand()*rand()%n+1;}

struct FHQTreap{
    #define ls(k) p[k].ls
    #define rs(k) p[k].rs
    
    int root,x,y,z,Ans,k,Now;
    inline FHQTreap(){x=y=z=0;root=0;}
    inline int NewNode(int val){
        Now=(top)?(Stack[top--]):(++tot); p[Now]=Node(val,1,0,0,random(INF));return Now;
    }
    inline void PushUp(int k){p[k].size=p[ls(k)].size+p[rs(k)].size+1;}
    inline void Split(int k,int val,int &x,int &y){
        if(!k){x=y=0;return;}
        if(p[k].val<=val){x=k;Split(rs(k),val,rs(x),y);PushUp(x);return;}
        else{y=k;Split(ls(k),val,x,ls(y));PushUp(y);return;}
    }
    inline int Merge(int a,int b){
        if(!a||!b) return a|b;
        if(p[a].key<p[b].key){ls(b)=Merge(a,ls(b));PushUp(b);return b;}
        else{rs(a)=Merge(rs(a),b);PushUp(a);return a;}
    }
    inline void Insert(int val){
        Split(root,val,x,y);z=Merge(x,NewNode(val));root=Merge(z,y);
    }
    inline void Delete(int val){
        Split(root,val,x,y);Split(x,val-1,x,z);if(z){Stack[++top]=z;z=Merge(ls(z),rs(z));}root=Merge(Merge(x,z),y);
    }
    inline int GetRank(int val){
        Split(root,val-1,x,y);Ans=p[x].size;root=Merge(x,y);return Ans;
    }
    inline int GetVal(int Size){
        k=root;
        while(k){
            if(p[ls(k)].size+1==Size) return k;
            else if(p[ls(k)].size+1<Size){Size-=p[ls(k)].size+1;k=rs(k);}
            else{k=ls(k);}
        }
        return k==0?INF:p[k].val;
    }
    inline int GetPre(int val){
        Split(root,val-1,x,y);k=x;while(rs(k)) k=rs(k);Ans=p[k].val;root=Merge(x,y);return k==0?-INF:Ans;
    }
    inline int GetNext(int val){
        Split(root,val,x,y);k=y;while(ls(k)) k=ls(k);Ans=p[k].val;root=Merge(x,y);return k==0?INF:Ans;
    }
    inline void Build(int l,int r){
        // printf("l=%d r=%d\n",l,r);
        for(int i=l;i<=r;i++) Insert(a[i]);
    }
};
FHQTreap Tr[M<<2];

struct SegmentTree{
    #define Ls(k) k<<1
    #define Rs(k) k<<1|1
    int L,R,mid,Ans;
    inline int GetRank(int k,int l,int r,int z,int y,int x){
        if(l==z&&r==y){return Tr[k].GetRank(x);}
        int mid=(l+r)>>1;
        if(y<=mid) return GetRank(Ls(k),l,mid,z,y,x);
        else if(z>mid) return GetRank(Rs(k),mid+1,r,z,y,x);
        else return GetRank(Ls(k),l,mid,z,mid,x)+GetRank(Rs(k),mid+1,r,mid+1,y,x);
    }
    inline int GetVal(int Rank,int l,int r){
        L=0;R=1e8;Ans=L;
        while(L<=R){
            int mid=(L+R)>>1;
            if(GetRank(1,1,n,l,r,mid)+1<=Rank){L=mid+1;Ans=mid;}else R=mid-1;
        }
        return Ans;
    }
    inline void Change(int k,int l,int r,int w,int x){
        Tr[k].Delete(a[w]);Tr[k].Insert(x);
        if(l==r) return;
        int mid=(l+r)>>1;
        if(w<=mid) Change(Ls(k),l,mid,w,x);
        else Change(Rs(k),mid+1,r,w,x);
    }
    inline int GetPre(int k,int l,int r,int z,int y,int x){
        if(l==z&&r==y) return Tr[k].GetPre(x);
        int mid=(l+r)>>1;
        if(y<=mid) return GetPre(Ls(k),l,mid,z,y,x);
        else if(z>mid) return GetPre(Rs(k),mid+1,r,z,y,x);
        else return Max(GetPre(Ls(k),l,mid,z,mid,x),GetPre(Rs(k),mid+1,r,mid+1,y,x));
    }
    inline int GetNext(int k,int l,int r,int z,int y,int x){
        if(l==z&&r==y) return Tr[k].GetNext(x);
        int mid=(l+r)>>1;
        if(y<=mid) return GetNext(Ls(k),l,mid,z,y,x);
        else if(z>mid) return GetNext(Rs(k),mid+1,r,z,y,x);
        else return Min(GetNext(Ls(k),l,mid,z,mid,x),GetNext(Rs(k),mid+1,r,mid+1,y,x));
    }
    inline void Build(int k,int l,int r){
        // printf("k=%d l=%d r=%d\n",k,l,r);
        Tr[k].Build(l,r);
        if(l==r) return;
        int mid=(l+r)>>1;
        Build(Ls(k),l,mid);Build(Rs(k),mid+1,r);
    }
}st;

inline void Init(){
    read(n);read(m);
    for(int i=1;i<=n;i++) read(a[i]);
    st.Build(1,1,n);
    // printf("Completing Build\n");
}

inline void Solve(){
    for(int i=1;i<=m;i++){
        int op,l,r,k;
        // printf("i=%d\n",i);
        read(op);
        if(op==1){
            read(l);read(r);read(k);
            printf("%d\n",st.GetRank(1,1,n,l,r,k)+1);
        }
        else if(op==2){
            read(l);read(r);read(k);
            printf("%d\n",st.GetVal(k,l,r));
        }
        else if(op==3){
            read(l);read(r);st.Change(1,1,n,l,r);
            a[l]=r;
        }
        else if(op==4){
            read(l);read(r);read(k);
            printf("%d\n",st.GetPre(1,1,n,l,r,k));
        }
        else if(op==5){
            read(l);read(r);read(k);
            printf("%d\n",st.GetNext(1,1,n,l,r,k));
        }
    }
}

int main(){
    // freopen("my.in","r",stdin);
    // freopen("my.out","w",stdout);
    Init();Solve();return 0;
}
posted @ 2021-12-03 16:49  hyl天梦  阅读(47)  评论(0编辑  收藏  举报