【TYVJ1730】【洛谷P3380】—二逼平衡树(树套树)

传送门

发现树套树也不是很难嘛

当然很难调

然而开始我连树套树怎么写都不知道

手动yyyy了两发

WaWa了之后找了份标程对拍,拍了之后又调

弄了大半天终于搞定了

自己写的是外层线段树套内层FHQFHQ-TreapTreap

对于线段树每一个区间节点,将区间建成一个TreapTreap

然后线段树将询问区间分成lognlogn个区间

每个lognlognTreapTreap上统计答案

复杂度O(nlog2n)O(nlog^2n)

具体细节看代码

洛谷上开O2O2莫名RERE

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    char ch=getchar();
    int res=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res*f;
}
const int N=5000005;
const int inf=2147483647;
int n,m,a[N],mx;
namespace FHQ_Treap{
    int son[N][2],siz[N],val[N],key[N],tot;
    #define lc(u) son[u][0]
    #define rc(u) son[u][1]
    void write(int u){//调试语句,按从小到大遍历一个Treap
        if(son[u][0])write(son[u][0]);
        cout<<val[u]<<" ";
        if(son[u][1])write(son[u][1]);
    }
    inline int addnode(int k){
        int u=++tot;
        val[tot]=k,key[tot]=rand();
        siz[tot]=1;return tot;
    }
    inline void pushup(int u){
        siz[u]=siz[lc(u)]+siz[rc(u)]+1;
    }
    void merge(int &u,int r1,int r2){
        if(!r1||!r2){u=r1+r2;return;}
        if(key[r1]<key[r2])u=r1,merge(rc(u),rc(r1),r2);
        else u=r2,merge(lc(u),r1,lc(r2));
        pushup(u);
    }
    void split(int u,int &r1,int &r2,int v){
        if(u==0){r1=r2=0;return;}
        if(val[u]<=v){
            r1=u,split(rc(u),rc(r1),r2,v);
        }
        else r2=u,split(lc(u),r1,lc(r2),v);
        pushup(u);
    }
    inline int getrk(int rt,int k){
        int r1,r2;
        split(rt,r1,r2,k-1);
        int res=siz[r1];
        merge(rt,r1,r2);
        return res;
    }
    inline int insert(int &rt,int v){
        int u=addnode(v),r1,r2;
        split(rt,r1,r2,v);
        merge(r1,r1,u);
        merge(rt,r1,r2);
    }
    inline int delet(int &rt,int v){
        int r1,r2,r3;
        split(rt,r1,r2,v);
        split(r1,r1,r3,v-1);
        merge(r3,lc(r3),rc(r3));
        merge(r1,r1,r3);
        merge(rt,r1,r2);
    }
    inline int pre(int rt,int v){
        int r1,r2;
        split(rt,r1,r2,v-1);
        if(!r1)return -inf;
        int u=r1;
        while(rc(u))u=rc(u);
        merge(rt,r1,r2);
        return val[u];
    }
    inline int nxt(int rt,int v){
        int r1,r2;
        split(rt,r1,r2,v);
        if(!r2)return inf;
        int u=r2;
        while(lc(u))u=lc(u);
        merge(rt,r1,r2);
        return val[u];
    }
    #undef lc
    #undef rc
}
using namespace FHQ_Treap;
namespace Seg{
    int rt[N];
    #define lc (u<<1)
    #define rc ((u<<1)|1)
    #define mid ((l+r)>>1)
    void buildtree(int u,int l,int r){
        for(int i=l;i<=r;++i)insert(rt[u],a[i]);
        if(l==r)return;
        buildtree(lc,l,mid);
        buildtree(rc,mid+1,r);
    }
    int queryrk(int u,int l,int r,int st,int des,int k){
        if(st<=l&&r<=des)return getrk(rt[u],k);
        int res=0;
        if(st<=mid)res+=queryrk(lc,l,mid,st,des,k);
        if(mid<des)res+=queryrk(rc,mid+1,r,st,des,k);
        return res;
    }
    void update(int u,int l,int r,int pos,int k){
        delet(rt[u],a[pos]),insert(rt[u],k);
        if(l==r)return;
        if(pos<=mid)update(lc,l,mid,pos,k);
        else update(rc,mid+1,r,pos,k);
    }
    int querypre(int u,int l,int r,int st,int des,int k){
        if(st<=l&&r<=des)return pre(rt[u],k);
        int res=-inf;
        if(st<=mid)res=max(res,querypre(lc,l,mid,st,des,k));
        if(mid<des)res=max(res,querypre(rc,mid+1,r,st,des,k));
        return res;
    }
    int querynxt(int u,int l,int r,int st,int des,int k){
        if(st<=l&&r<=des)return nxt(rt[u],k);
        int res=inf;
        if(st<=mid)res=min(res,querynxt(lc,l,mid,st,des,k));
        if(mid<des)res=min(res,querynxt(rc,mid+1,r,st,des,k));
        return res;
    }
}
using namespace Seg;
inline int kth(int st,int des,int k){
    int ans=0,l=0,r=mx+1;
    while(l<r){
        int pk=queryrk(1,1,n,st,des,mid);
        if(pk<k)l=mid+1;
        else r=mid;
    }
    return l-1;
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)a[i]=read(),mx=max(mx,a[i]);
    buildtree(1,1,n);
    for(int i=1;i<=m;i++){
        int op=read();
        switch(op){
            case 1:{
                int l=read(),r=read(),k=read();
                cout<<queryrk(1,1,n,l,r,k)+1<<'\n';
                break;
            }
            case 2:{
                int l=read(),r=read(),k=read();
                cout<<kth(l,r,k)<<'\n';
                break;
            }
            case 3:{
                int pos=read(),k=read();
                update(1,1,n,pos,k);a[pos]=k;
                break;
            }
            case 4:{
                int l=read(),r=read(),k=read();
                cout<<querypre(1,1,n,l,r,k)<<'\n';
                break;
            }
            case 5:{
                int l=read(),r=read(),k=read();
                cout<<querynxt(1,1,n,l,r,k)<<'\n';
                break;
            }
        }
    }
}
posted @ 2019-01-24 21:01  Stargazer_cykoi  阅读(106)  评论(0编辑  收藏  举报