zoukankan      html  css  js  c++  java
  • 文艺平衡Splay树学习笔记(2)

    本blog会讲一些简单的Splay的应用,包括但不局限于

    1. Splay 维护数组下标,支持区间reserve操作,解决区间问题

    2. Splay 的启发式合并(按元素多少合并)

    3. 线段树+Splay 大常数树套树

    一、Splay维护区间下标解决区间翻转问题

    思想: 对于数组的下标是不可重复的,我们使用平衡树维护下标,利用Splay的splay操作,让区间都在一棵子树内。

    然后直接输出这颗子树的维护信息,由于维护的是子树信息,那么父亲的信息一定可以由两个儿子推出。

    于是就可以类似于线段树的操作了(用儿子信息维护父亲信息)。 

    [LuoGu 模板] 文艺平衡树 : 维护区间翻转,输出最终区间形态。

    Solution : 

    考虑splay函数的实质,就是把节点x转到目标节点,并且让Splay树保持BST的性质。

    那么显然,对于维护序列下标,其维护的值便是元素对于数组的位置。(一个节点左边儿子子树的位置都小于该节点)

    对于一个区间进行翻转,那么事实上就是 把l和r下标交换,l+1和r-1下标交换...

    那么如何确定这个区间呢,不妨把[l-1]转到根节点,[r+1]转到根节点的右儿子,那么对于根节点右儿子的左儿子所在子树

    就可以描述为[l,r]区间。

    然而,对于Splay本身来说是不能出现下标为0的情况的,否则会死循环,在(1)中已经讲的非常明确了,所以我们仍然加入一个哨兵节点,对于所有区间均+1

    在代码中的实现是这样的。

    需要注意的是,特殊的,对于维护位置(下标)是不会出现重复元素的,那么所有节点cnt的值都是1,就省略了。

    最后这颗Splay的中序遍历就是最终区间。

    # include <bits/stdc++.h>
    # define inf (0x3f3f3f3f)
    using namespace std;
    const int N=2e5+10;
    inline int read()
    {
        int X=0,w=0; char c=0;
        while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
        while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
        return w?-X:X;
    }
    void write(int x) {
        if (x<0) putchar('-'),x=-x;
        if (x>9) write(x/10);
        putchar(x%10+'0');
    }
    void writeln(int x){
        write(x);putchar('
    ');
    }
    struct Splay{
        # define ls(x) (t[x][0])
        # define rs(x) (t[x][1])
        int t[N][2],size[N],val[N],par[N];
        bool rev[N];
        int root,tot;
        Splay(){ root=0,tot=0;insert(-inf);insert(inf);}
        int check (int x) { return rs(par[x])==x;}
        void pushup(int x) { size[x]=size[ls(x)]+size[rs(x)]+1;}
        void rotate(int x) {
            int y=par[x],k=check(x);
            t[y][k]=t[x][k^1]; par[t[x][k^1]]=y;
            t[x][k^1]=y;
            t[par[y]][check(y)]=x; par[x]=par[y]; par[y]=x;
            pushup(y); pushup(x);
        }
        void splay(int x,int goal=0) {
            while (par[x]!=goal) {
                int y=par[x],z=par[y];
                if (z!=goal) rotate(check(x)==check(y)?y:x);
                rotate(x);
            }
            if (!goal) root=x;
        }
        void down(int x) {
            if (rev[x]) {
                swap(ls(x),rs(x));
                rev[ls(x)]^=1; rev[rs(x)]^=1;
                rev[x]=0;
            }
        }
        void insert(int x){
            int cur=root,p=0;
            while (cur && val[cur]!=x)
              p=cur,cur=t[cur][x>val[cur]];
            cur=++tot;
            if (p) t[p][x>val[p]]=cur;
            t[cur][0]=t[cur][1]=0;
            val[cur]=x; par[cur]=p;
            size[cur]=1;
            splay(cur);
        }
        int kth_id(int k) {
            int cur=root;
            while (true) {
                down(cur);
                if (t[cur][0] && k<=size[ls(cur)]) cur=ls(cur);
                else if (k>size[ls(cur)]+1) {
                    k-=size[ls(cur)]+1;
                    cur=rs(cur);
                } else return cur;
            }
        }
        void reserve(int l,int r) {
            int x=kth_id(l),y=kth_id(r+2);
            splay(x); splay(y,x);
            rev[ls(y)]^=1;
        }
        void print(int x) {
            down(x);
            if (ls(x)) print(ls(x));
            if (val[x]!=-inf&&val[x]!=inf) printf("%d ",val[x]);
            if (rs(x)) print(rs(x));
        }
    }tr;
    int main()
    {
        int n=read(),m=read();
        for (int i=1;i<=n;i++) tr.insert(i);
        for (int i=1;i<=m;i++) {
            int l=read(),r=read();
            tr.reserve(l,r);
        }
        tr.print(tr.root);
        return 0;
    }
    P3391 【模板】文艺平衡树(Splay)

     [例题 : 序列终结者]

    用Splay维护3个操作

    1 L R V : 区间[L,R]每个元素+V

    2 L R  :将区间[L,R]翻转

    3 L R  :输出区间[L,R]的最小值

    Hint : 元素初始值都为 0 

    Solution: 

    显然我们可以使用上述方法维护一棵平衡树,还是维护下标,我们发现splay或者rotate一下,树维护下标的性质是不会改变的。

    所以仍然可以在节点维护一个加法标记,当翻转前下传即可。

    # include<bits/stdc++.h>
    # define inf (0x3f3f3f3f)
    using namespace std;
    const int N=1e5+10;
    int n,m,a[N];
    struct Splay{
        # define ls(x) (t[x][0])
        # define rs(x) (t[x][1])
        int t[N][2],par[N],size[N],val[N],mx[N],add[N];
        int root,tot;
        bool rev[N];
        int check(int x){return rs(par[x])==x; }
        void up(int x) {
            size[x]=size[ls(x)]+size[rs(x)]+1;
            mx[x]=max(max(mx[ls(x)],mx[rs(x)]),val[x]);
        }
        void down(int x) {
            int &l=ls(x),&r=rs(x);
            if (add[x]) {
                if (l) add[l]+=add[x],val[l]+=add[x],mx[l]+=add[x];
                if (r) add[r]+=add[x],val[r]+=add[x],mx[r]+=add[x]; 
            }
            if (rev[x]) rev[l]^=1,rev[r]^=1,swap(l,r);
            rev[x]=add[x]=0;
        }
        void rotate(int x) {
            int y=par[x],k=check(x);
            down(x); down(y);
            t[y][k]=t[x][k^1]; par[t[x][k^1]]=y;
            t[x][k^1]=y; t[par[y]][check(y)]=x;
            par[x]=par[y];par[y]=x;
            up(y); up(x);
        }
        void splay(int x,int goal=0) 
        {
            while (par[x]!=goal) {
                int y=par[x],z=par[y];
                if (z!=goal) rotate((check(x)==check(y))?y:x);
                rotate(x);
            }
            if (!goal) root=x;
        }
        int build(int l,int r,int fa) {
            if(l>r) return 0;
            int x=++tot,mid=(l+r)>>1;
            par[x]=fa,val[x]=mx[x]=a[mid];
            ls(x)=build(l,mid-1,x);
            rs(x)=build(mid+1,r,x);
            up(x); return x;
        }
        int kth_id(int k) {
            int cur=root;
            while (cur) {
                down(cur);
                if (t[cur][0] && k<=size[ls(cur)]) cur=ls(cur);
                else if (k>size[ls(cur)]+1) {
                    k-=size[ls(cur)]+1;
                    cur=rs(cur);
                } else return cur;
            }
        }
        int kth_val(int k) {
            int p=kth_id(k);
            return val[p];
        }
        void reserve(int l,int r)
        {
            int x=kth_id(l),y=kth_id(r+2);
            splay(x); splay(y,x);
            rev[ls(y)]^=1;
        }
        int GetMax(int l,int r) {
            int x=kth_id(l),y=kth_id(r+2);
            splay(x); splay(y,x);
            return mx[ls(y)];
        }
        int Add(int l,int r,int d)
        {
            int x=kth_id(l),y=kth_id(r+2);
            splay(x); splay(y,x); val[ls(y)]+=d;
            add[ls(y)]+=d; mx[ls(y)]+=d;
        }
    }tr;
    int main()
    {
        scanf("%d%d",&n,&m);
        memset(a,0,sizeof(a));
        tr.mx[0]=a[1]=a[n+2]=-inf; 
        tr.root=tr.build(1,n+2,0);
        while (m--) {
            int op,l,r,d;
            scanf("%d%d%d",&op,&l,&r);
            if (op==1) scanf("%d",&d),tr.Add(l,r,d);
            else if (op==2) tr.reserve(l,r);
            else if (op==3) printf("%d
    ",tr.GetMax(l,r));
        }
        return 0;
    } 
    序列终结者.cpp

     二、Splay的启发式合并(按元素多少合并)

    P3224 [HNOI2012]永无乡

    维护两个操作:

    一开始所有元素都独立。

    1 . 合并x,y

    2 . 在节点x连通块内求节点排名为k的元素编号。

    Sol : 首先,对于每个元素都维护一棵平衡树,由于我们是数组模拟链表,所以在"指针池"中,只需要记录根是谁。

    就可以维护一棵平衡树森林了,我们只要求在平衡树森林中总节点个数不超过"指针池"大小即可。

    当合并节点x,y的时候,若以x所在节点的平衡树和y所在节点平衡树合并的时候,按节点个数合并即可,尽可能保证元素多的Splay树不改变,

    然后把元素少的Splay树遍历依次,把所有拥有的元素插入到元素多的Splay树中

    为了处理方便,我们令第i棵子树根的编号为father(i)

    # include <bits/stdc++.h>
    using namespace std;
    const int N=3e5+10;
    map<int,int>Hash;
    int t[N][2],par[N],root[N],size[N],cnt[N],val[N];
    int n,m,tot,f[N];
    # define ls(x) t[x][0]
    # define rs(x) t[x][1]
    inline int read()
    {
        int X=0,w=0; char c=0;
        while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
        while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
        return w?-X:X;
    }
    inline void write(int x)
    {
        if (x<0) putchar('-'),x=-x;
        if (x>9) write(x/10);
        putchar('0'+x%10);
    }
    int check(int x) { return rs(par[x])==x; }
    void up(int x){
        size[x]=size[ls(x)]+size[rs(x)]+cnt[x];
    }
    void rotate(int x){
        int y=par[x],k=check(x);
        t[y][k]=t[x][k^1]; par[t[x][k^1]]=y;
        t[x][k^1]=y; t[par[y]][check(y)]=x;
        par[x]=par[y]; par[y]=x;
        up(y); up(x);
    }
    void splay(int x,int goal) {
        while (par[x]!=goal) {
            int y=par[x],z=par[y];
            if (z!=goal) {
                if (check(x)==check(y)) rotate(y);
                else rotate(x);
            }
            rotate(x);
        }
        if (goal<=n) root[goal]=x;
    }
    void insert(int rt,int x) {
        int cur=root[rt],p=rt;
        while (cur && val[cur]!=x)
         p=cur,cur=t[cur][x>val[cur]];
        if (cur) cnt[cur]++;
        else {
            cur=++tot;
            if (p>n) t[p][x>val[p]]=cur;
            ls(cur)=rs(cur)=0;
            par[cur]=p; val[cur]=x;
            size[cur]=cnt[cur]=1;
        }
        splay(cur,rt);
    }
    int kth(int rt,int k) {
        int cur=root[rt];
        if (k>size[cur]||k<0) return -1;
        while (true) {
            if (t[cur][0]&&k<=size[ls(cur)]) cur=ls(cur);
            else if (k>size[ls(cur)]+cnt[cur]) {
                k-=size[ls(cur)]+cnt[cur];
                cur=rs(cur);
            } else return val[cur];
        }
    }
    int father(int x)
    {
        if (f[x]==x) return x;
        return f[x]=father(f[x]);
    }
    void dfs(int tr1,int tr2)
    {
        if (ls(tr1)) dfs(ls(tr1),tr2);
        if (rs(tr1)) dfs(rs(tr1),tr2);
        insert(tr2,val[tr1]);
    }
    void merge(int u,int v)
    {
        int fx=father(u),fy=father(v);
        if (size[root[fx]]>size[root[fy]]) swap(fx,fy);
        f[fx]=fy;
        dfs(root[fx],fy);
    }
    int main()
    {
        n=read();m=read();
        for (int i=1;i<=n;i++) f[i]=i,root[i]=i+n;
        for (int i=1;i<=n;i++){
            int x=read();  Hash[x]=i;
            val[i+n]=x; cnt[i+n]=size[i+n]=1; par[i+n]=i;
        }
        tot=n<<1;
        for (int i=1;i<=m;i++) {
            int u=read(),v=read();
            merge(u,v);
        }
        int Q=read();
        char op[3];
        while (Q--) {
            scanf("%s",op);int x=read(),y=read();
            if (op[0]=='B') merge(x,y);
            else {
                int ans=kth(father(x),y);
                if (ans==-1) write(-1),putchar('
    ');
                else write(Hash[ans]),putchar('
    ');
            }
        }
        return 0;
    }
    永无乡.cpp

    三. 线段树+Splay 大常数树套树

    【模板】二逼平衡树(树套树)

    // luogu-judger-enable-o2
    // luogu-judger-enable-o2
    // luogu-judger-enable-o2
    # pragma GCC optimize(3)
    # include <cstdio>
    # define il inline
    # define Rint register int
    using namespace std;
    const int inf=2147483647;
    const int N=5e4+5;
    int a[N];
    int n,m,Lim;
    il int max(int a,int b) {
        return (a<b)?b:a;
    }
    il int min(int a,int b) {
        return (a>b)?b:a;
    }
    il int read()
    {
        int X=0,w=0; char c=0;
        while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
        while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
        return w?-X:X;
    }
    il void write(int x)
    {
        if (x<0) putchar('-'),x=-x;
        if (x>9) write(x/10);
        putchar('0'+x%10);
    }
    il void writeln(int x){write(x);putchar('
    ');}
    struct SegmentTree{
        int l,r,root;
    }tr[N<<2];
    struct Splay{
        # define ls(x) (t[x][0])
        # define rs(x) (t[x][1])
        int t[N*50][2],cnt[N*50],val[N*50],size[N*50],par[N*50];
        int tot;
        Splay() { tot=0; }
        il int check(int x) { return rs(par[x])==x; }
        il void up(int x){
            size[x]=size[ls(x)]+size[rs(x)]+cnt[x];
        }
        il void rotate(int x){
            int y=par[x],k=check(x);
            t[y][k]=t[x][k^1]; par[t[x][k^1]]=y;
            t[x][k^1]=y; t[par[y]][check(y)]=x;
            par[x]=par[y]; par[y]=x;
            up(y); up(x);
        }
        il void splay(int node,int x,int goal) {
            while (par[x]!=goal) {
                int y=par[x],z=par[y];
                if (z!=goal) {
                    if (check(x)==check(y)) rotate(y);
                    else rotate(x);
                }
                rotate(x);
            }
            if (!goal) tr[node].root=x;
        }
        il void insert(int node,int x) {
            int cur=tr[node].root,p=0;
            if (!cur) {
                cur=++tot; tr[node].root=cur;
                ls(cur)=rs(cur)=0;
                par[cur]=0; val[cur]=x;
                size[cur]=cnt[cur]=1;
                return;
            }
            while (cur && val[cur]!=x)
             p=cur,cur=t[cur][x>val[cur]];
            if (cur) cnt[cur]++;
            else {
                cur=++tot;
                if (p) t[p][x>val[p]]=cur;
                ls(cur)=rs(cur)=0;
                par[cur]=p; val[cur]=x;
                size[cur]=cnt[cur]=1;
            }
            splay(node,cur,0);
        }
        il void find(int node,int x){
            int cur=tr[node].root;
            if (!cur) return;
            while (t[cur][x>val[cur]] && val[cur]!=x)
                cur=t[cur][x>val[cur]];
            splay(node,cur,0);
        }
        il int pre_id(int node,int x) {
            find(node,x); int cur=tr[node].root;
            if (val[cur]<x) return cur;
            cur=ls(cur);
            while (rs(cur)) cur=rs(cur);
            return cur;
        }
        il int pre_val(int node,int x){
            find(node,x); int cur=tr[node].root;
            if (val[cur]<x) return val[cur];
            cur=ls(cur);
            while (rs(cur)) cur=rs(cur);
            return val[cur];
        }
        il int suc_id(int node,int x) {
            find(node,x); int cur=tr[node].root;
            if (val[cur]>x) return cur;
            cur=rs(cur);
            while (ls(cur)) cur=ls(cur);
            return cur;
        }
        il int suc_val(int node,int x){
            find(node,x); int cur=tr[node].root;
            if (val[cur]>x) return val[cur];
            cur=rs(cur);
            while (ls(cur)) cur=ls(cur);
            return val[cur];
        }
        il void erase(int node,int x){
            int last=pre_id(node,x);
            int next=suc_id(node,x);
            splay(node,next,0); splay(node,last,next);
            int d=rs(last);
            if (cnt[d]>1) cnt[d]--,splay(node,d,0);
            else rs(last)=0;
            up(last);
        }
        il int rank(int node,int x) {
            find(node,x); int cur=tr[node].root;
            if (val[cur]>=x) return size[ls(cur)]-1;
            else return size[ls(cur)]+cnt[cur]-1;
        }
        # undef ls
        # undef rs
    }t;
    # define lson 2*x,l,mid
    # define rson 2*x+1,mid+1,r
    # define mid ((l+r)>>1)
    int Ans;
    il void SegBuild(int x,int l,int r)
    {
        t.insert(x,-inf); t.insert(x,inf);
        if (l==r) return;
        SegBuild(lson); SegBuild(rson);
    }
    il void SegInsert(int x,int l,int r,int pos,int val)
    {
        t.insert(x,val);
        if (l==r) return;
        if (pos<=mid) SegInsert(lson,pos,val);
        else SegInsert(rson,pos,val);
    }
    il void SegRank(int x,int l,int r,int val,int opl,int opr)
    {
        if (opl<=l&&r<=opr) {
            Ans+=t.rank(x,val);
            return;
        }
        if (opl<=mid) SegRank(lson,val,opl,opr);
        if (opr>mid) SegRank(rson,val,opl,opr);
    }
    il void SegUpdate(int x,int l,int r,int pos,int val)
    {
        t.erase(x,a[pos]); t.insert(x,val);
        if (l==r) { a[pos]=val; return; }
        if (pos<=mid) SegUpdate(lson,pos,val);
        else SegUpdate(rson,pos,val);
    }
    il void SegPre(int x,int l,int r,int opl,int opr,int val)
    {
        if (opl<=l&&r<=opr) {
            Ans=max(Ans,t.pre_val(x,val));
            return;
        }
        if (opl<=mid) SegPre(lson,opl,opr,val);
        if (opr>mid) SegPre(rson,opl,opr,val);
    }
    il void SegSuc(int x,int l,int r,int opl,int opr,int val)
    {
        if (opl<=l&&r<=opr) {
            Ans=min(t.suc_val(x,val),Ans);
            return;
        }
        if (opl<=mid) SegSuc(lson,opl,opr,val);
        if (opr>mid) SegSuc(rson,opl,opr,val);
    }
    il int SegKth(int opl,int opr,int k)
    {
        int l=0,r=Lim,ans;
        while (l<=r) {
            int Mid=(l+r)>>1;
            Ans=0; SegRank(1,1,n,Mid,opl,opr);
            if (Ans+1>k) r=Mid-1;
            else l=Mid+1,ans=Mid;
        }
        return ans;
    }
    int main()
    {
        n=read();m=read();
        SegBuild(1,1,n);
        for (Rint i=1;i<=n;i++) {
            a[i]=read(); Lim=max(Lim,a[i]);
            SegInsert(1,1,n,i,a[i]);
        }
        for (Rint i=1;i<=m;i++) {
            int op=read(),l=read(),r=read(),k;
            if (op==1) k=read(),Ans=0,SegRank(1,1,n,k,l,r),writeln(Ans+1);
            if (op==2) k=read(),writeln(SegKth(l,r,k));
            if (op==3) SegUpdate(1,1,n,l,r);
            if (op==4) k=read(),Ans=-inf,SegPre(1,1,n,l,r,k),writeln(Ans);
            if (op==5) k=read(),Ans=inf,SegSuc(1,1,n,l,r,k),writeln(Ans);
        }
        return 0;
    }
    二逼平衡树(Splay).cpp
    # include <bits/stdc++.h>
    # define inf (2147483647)
    using namespace std;
    const int N=4e6+10;
    int n,m,Lim,tot;
    int a[N];
    struct Treap_Node{
        int val,key,cnt,size;
        int ch[2];
    }t[N];
    struct Treap {
        # define ls t[x].ch[0]
        # define rs t[x].ch[1]
        void up(int &x){t[x].size=t[x].cnt+t[ls].size+t[rs].size;}
        void rotate(int &x,int d)
        {
            int son=t[x].ch[d];
            t[x].ch[d]=t[son].ch[d^1];
            t[son].ch[d^1]=x;
            up(x); up(x=son);
        }
        void insert(int &x,int val)
        {
            if (!x) { 
                x=++tot;
                t[x].size=t[x].cnt=1;
                t[x].val=val;
                t[x].key=rand();
                return;
            }
            t[x].size++;
            if (t[x].val==val) { t[x].cnt++; return;}
            int d=t[x].val<val;
            insert(t[x].ch[d],val);
            if (t[x].key>t[t[x].ch[d]].key) rotate(x,d);
        }
        void erase(int &x,int val)
        {
            if (!x) return;
            if (t[x].val==val) {
                if (t[x].cnt>1) { t[x].cnt--; t[x].size--; return;}
                int d=t[ls].key>t[rs].key;
                if (ls==0||rs==0) x=ls+rs;
                else rotate(x,d),erase(x,val);
            } else t[x].size--,erase(t[x].ch[t[x].val<val],val);
        }
        inline int rank(int &x,int val){
            if (!x) return 0;
            if (t[x].val==val) return t[ls].size;
            if (t[x].val>val) return rank(ls,val);
            return t[x].cnt+t[ls].size+rank(rs,val); 
        }
        int find(int &rt,int k)
        {
            int x=rt;
            while (1) {
                if (k<=t[ls].size) x=ls;
                else if (k>t[x].cnt+t[ls].size) k-=t[x].cnt+t[ls].size,x=rs;
                else return t[x].val;
            } 
        }
        inline int pre(int &x,int val)
        {
            if (!x) return -inf;
            if (t[x].val>=val) return pre(ls,val);
            return max(pre(rs,val),t[x].val);
        }
        int nex(int &x,int val)
        {
            if (!x) return inf;
            if (t[x].val<=val) return nex(rs,val);
            return min(nex(ls,val),t[x].val);
        }
        #undef ls
        #undef rs 
    }tr;
    struct Segment_Tree{
        int l,r,root;
    }tree[N];
    # define lson (x<<1),l,mid
    # define rson (x<<1)+1,mid+1,r
    # define mid ((l+r)>>1)
    void SegInsert(int x,int l,int r,int pos,int val)
    {
        tr.insert(tree[x].root,val);
        if (l==r) return;
        if (pos<=mid) SegInsert(lson,pos,val);
        else SegInsert(rson,pos,val);
    }
    int SegRank(int x,int l,int r,int ql,int qr,int val)
    {
        if (ql<=l&&r<=qr) return tr.rank(tree[x].root,val);
        int ret=0;
        if (ql<=mid) ret+=SegRank(lson,ql,qr,val);
        if (qr>mid) ret+=SegRank(rson,ql,qr,val);
        return ret;
    }
    void SegUpdate(int x,int l,int r,int pos,int val)
    {
        tr.insert(tree[x].root,val);
        tr.erase(tree[x].root,a[pos]);
        if (l==r) { a[pos]=val; return;}
        if (pos<=mid) SegUpdate(lson,pos,val);
        else SegUpdate(rson,pos,val);
    }
    int SegPre(int x,int l,int r,int ql,int qr,int val)
    {
        if (ql<=l&&r<=qr) return tr.pre(tree[x].root,val);
        int ret=-inf;
        if (ql<=mid) ret=max(ret,SegPre(lson,ql,qr,val));
        if (qr>mid) ret=max(ret,SegPre(rson,ql,qr,val));
        return ret;
    }
    int SegSuc(int x,int l,int r,int ql,int qr,int val)
    {
        if (ql<=l&&r<=qr) return tr.nex(tree[x].root,val);
        int ret=inf;
        if (ql<=mid) ret=min(ret,SegSuc(lson,ql,qr,val));
        if (qr>mid) ret=min(ret,SegSuc(rson,ql,qr,val));
        return ret;
    }
    # undef lson
    # undef rson
    # undef mid
    int SegKth(int l,int r,int k)
    {
        int L=0,R=Lim+1,Ans;
        while (L<=R) {
            int Mid=(L+R)>>1;
            if (SegRank(1,1,n,l,r,Mid)+1>k) R=Mid-1;
            else Ans=Mid,L=Mid+1;
        }
        return Ans;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) {
            int t; scanf("%d",&t); Lim=max(Lim,t);
            a[i]=t;    SegInsert(1,1,n,i,t);
        }
        while (m--) {
            int op,l,r,k; scanf("%d",&op);
            if (op==1) scanf("%d%d%d",&l,&r,&k),printf("%d
    ",SegRank(1,1,n,l,r,k)+1);
            if (op==2) scanf("%d%d%d",&l,&r,&k),printf("%d
    ",SegKth(l,r,k));
            if (op==3) scanf("%d%d",&l,&r),SegUpdate(1,1,n,l,r);
            if (op==4) scanf("%d%d%d",&l,&r,&k),printf("%d
    ",SegPre(1,1,n,l,r,k));
            if (op==5) scanf("%d%d%d",&l,&r,&k),printf("%d
    ",SegSuc(1,1,n,l,r,k));
        }
        return 0;
    }
    二逼平衡树(Treap).cpp

     

  • 相关阅读:
    [CF1295E] Permutation Separation
    [APIO2010] 特别行动队
    [CF1296F] Berland Beauty
    [CEOI2004] 锯木厂选址
    [CF1334E] Divisor Paths
    Review 2020.11.14
    [CQOI2016] 手机号码
    [LEETCODE600] 不含连续1的非负整数
    [CF55D] Beautiful numbers
    内存取证工具volatility
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/10628090.html
Copyright © 2011-2022 走看看