zoukankan      html  css  js  c++  java
  • 【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<<'
    ';
                    break;
                }
                case 2:{
                    int l=read(),r=read(),k=read();
                    cout<<kth(l,r,k)<<'
    ';
                    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)<<'
    ';
                    break;
                }
                case 5:{
                    int l=read(),r=read(),k=read();
                    cout<<querynxt(1,1,n,l,r,k)<<'
    ';
                    break;
                }
            }
        }
    }
    
  • 相关阅读:
    逻辑即理性
    关于股市与经济的一点思考
    Objective-C Automatic Reference Counting (ARC)
    错误与异常
    Programming with Objective-C -- 属性的缺省实现
    视频容器格式与编码格式简介
    视频基础知识-封装格式和编码格式
    各种音视频编解码学习详解
    你的技术护城河是什么?--技术前沿代表了一个人的眼力和价值
    技术前沿--很多技术不了解细节也应该了解大概---知道能用来干什么--了解技术的价值
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/10366336.html
Copyright © 2011-2022 走看看