[bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)

Description

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

Input

第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继

Output

对于操作1,2,4,5各输出一行,表示查询结果

Sample Input

9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5

Sample Output

2
4
3
4
9

HINT

1.n和m的数据范围:n,m<=50000

2.序列中每个数的数据范围:[0,1e8]

3.虽然原题没有,但事实上5操作的k可能为负数

Solution

#include <stdio.h>
#include <stdlib.h>
#define N 50010
#define inf 0x7fffffff
#define opp 0x80000000
#define mid ((x>>1)+(y>>1)+(x&y&1))
#define dmax(x,y) ((x)>(y)?(x):(y))
#define dmin(x,y) ((x)<(y)?(x):(y))
#define RG register
#define inline __inline__ __attribute__((always_inline))

inline int Rin(){
    RG int x=0,c=getchar(),f=1;
    for(;c<48||c>57;c=getchar())
        if(!(c^45))f=-1;
    for(;c>47&&c<58;c=getchar())
        x=(x<<1)+(x<<3)+c-48;
    return x*f;
}

int n,m,a[N];

namespace Seg{
    struct Treap{
        struct Nt{
            Nt*ch[2];
            int s,w,v,r;

            Nt(RG int v,RG Nt*_) : v(v),r(rand()) {
                s=w=1;
                ch[0]=ch[1]=_;
            }

            inline void maintain(){
                s=w+ch[0]->s+ch[1]->s;
            }
        }*root,*null;

        Treap(){
            null=new Nt(0,0x0);
            null->s=null->w=0;
            null->r=inf;
            null->ch[0]=null->ch[1]=null;
            root=null;
        }

        void rotate(RG Nt*&o,RG int d){
            Nt*k=o->ch[1^d];
            o->ch[1^d]=k->ch[d];
            k->ch[d]=o;
            o->maintain();
            k->maintain();
            o=k;
        }

        void insert(RG Nt*&o,RG int v){
            if(o==null){
                o=new Nt(v,null);
                return;
            }
            o->s++;
            if(v==o->v)
                o->w++;
            else{
                RG int d=v > o->v;
                insert(o->ch[d],v);
                if(o->ch[d]->r < o->r)
                    rotate(o,1^d);
            }
        }

        void remove(RG Nt*&o,RG int v){
            if(o==null)
                return;
            if(o->v==v){
                if(o->w>1){
                    o->s--;
                    o->w--;
                    return;
                }
                if(o->ch[0]!=null && o->ch[1]!=null){
                    RG int d=o->ch[0]->r > o->ch[1]->r;
                    rotate(o,d);
                    remove(o->ch[d],v);
                }
                else o=o->ch[o->ch[0]==null];
            }
            else{
                o->s--;
                remove(o->ch[o->v < v],v);
            }
            if(o!=null)
                o->maintain();
        }

        inline int pre(RG int v){
            RG int ans=opp;
            for(RG Nt*o=root;o!=null;)
                v > o->v ? (ans=dmax(ans,o->v),o=o->ch[1]) : o=o->ch[0];
            return ans;
        }

        inline int nxt(RG int v){
            RG int ans=inf;
            for(RG Nt*o=root;o!=null;)
                v < o->v ? (ans=dmin(ans,o->v),o=o->ch[0]) : o=o->ch[1];
            return ans;
        }

        inline int rank(RG int v){
            RG int ans=0;
            for(Nt*o=root;o!=null;){
                RG int d= v==o->v? -1 : (o->v < v);
                if(d==-1){
                    ans+=o->ch[0]->s;
                    break;
                }
                d?(ans+=o->ch[0]->s+o->w,o=o->ch[1]):o=o->ch[0];
            }
            return ans;
        }
    }rt[N<<2];

    void build(RG int x,RG int y,RG int k){
        for(RG int i=x;i<=y;i++)
            rt[k].insert(rt[k].root,a[i]);
        if(x<y){
            build(x,mid,k<<1);
            build(mid+1,y,k<<1|1);
        }
    }

    void modify(RG int x,RG int y,RG int k,RG int pos,RG int num){
        rt[k].remove(rt[k].root,a[pos]);
        rt[k].insert(rt[k].root,num);
        if(x<y)
            pos<=mid ? modify(x,mid,k<<1,pos,num):
                modify(mid+1,y,k<<1|1,pos,num);
    }

    int getrank(RG int x,RG int y,RG int k,RG int l,RG int r,RG int num){
        if(x==l && y==r)
            return rt[k].rank(num);
        if(r<=mid)
            return getrank(x,mid,k<<1,l,r,num);
        if(l>mid)
            return getrank(mid+1,y,k<<1|1,l,r,num);
        return getrank(x,mid,k<<1,l,mid,num)+getrank(mid+1,y,k<<1|1,mid+1,r,num);
    }

    int getpre(RG int x,RG int y,RG int k,RG int l,RG int r,RG int num){
        if(x==l && y==r)
            return rt[k].pre(num);
        if(r<=mid)
            return getpre(x,mid,k<<1,l,r,num);
        if(l>mid)
            return getpre(mid+1,y,k<<1|1,l,r,num);
        return dmax(getpre(x,mid,k<<1,l,mid,num),getpre(mid+1,y,k<<1|1,mid+1,r,num));
    }

    int getnxt(RG int x,RG int y,RG int k,RG int l,RG int r,RG int num){
        if(x==l && y==r)
            return rt[k].nxt(num);
        if(r<=mid)
            return getnxt(x,mid,k<<1,l,r,num);
        if(l>mid)
            return getnxt(mid+1,y,k<<1|1,l,r,num);
        return dmin(getnxt(x,mid,k<<1,l,mid,num),getnxt(mid+1,y,k<<1|1,mid+1,r,num));
    }

    inline int getkth(RG int l,RG int r,RG int k){
        RG int x=0,y=1e8;
        while(x<=y)
            getrank(1,n,1,l,r,mid) < k ?
                x=mid+1:
                y=mid-1;
        if(getrank(1,n,1,l,r,x)>=k)
            x=getpre(1,n,1,l,r,x);
        return x;
    }
}

int main(){
    srand(‘K‘+‘a‘+‘i‘+‘b‘+‘a‘);
    n=Rin(),m=Rin();
    for(int i=1;i<=n;i++)
        a[i]=Rin();
    Seg::build(1,n,1);
    while(m--){
        RG int x,y,k,c=Rin();
        switch(c){
            case 1 :
                x=Rin(),y=Rin(),k=Rin();
                printf("%d\n",Seg::getrank(1,n,1,x,y,k)+1);
                break;
            case 2 :
                x=Rin(),y=Rin(),k=Rin();
                printf("%d\n",Seg::getkth(x,y,k));
                break;
            case 3 :
                x=Rin(),k=Rin();
                Seg::modify(1,n,1,x,k);
                a[x]=k;
                break;
            case 4 :
                x=Rin(),y=Rin(),k=Rin();
                printf("%d\n",Seg::getpre(1,n,1,x,y,k));
                break;
            case 5 :
                x=Rin(),y=Rin(),k=Rin();
                printf("%d\n",Seg::getnxt(1,n,1,x,y,k));
                break;
            default : break;
        }
    }
    return 0;
}
时间: 2024-10-21 16:09:28

[bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)的相关文章

【bzoj3196】 Tyvj 1730 二逼平衡树 线段树套Treap

题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) 输入 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数,表示有序序列下面有m行,opt表示操作标号若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名若opt=2 则为操

bzoj 3196 &amp;&amp; luogu 3380 JoyOI 1730 二逼平衡树 (线段树套Treap)

链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3196 题面; 3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 6372  Solved: 2406[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为

[TYVJ 1730]二逼平衡树 线段树套平衡树

来一发树套树.1A也是很感动QAQ 就是时间复杂度略大.而且好像还有其他打法. 谨以此纪念此类型树套树入门 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> using namespace std; #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define N 51000 #define size(x) ((x)

【线段树套平衡树】【pb_ds】bzoj3196 Tyvj 1730 二逼平衡树

线段树套pb_ds里的平衡树,在洛谷OJ上测试,后三个测试点TLE #include<cstdio> #include<algorithm> #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/tree_policy.hpp> #define N 50010 #define INF 2147483647 using namespace std; using namespace __gnu_pb

Bzoj3196 Tyvj 1730 二逼平衡树

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3350  Solved: 1324 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行

bzoj3196 二逼平衡树 线段树套平衡树

题意:您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) 题解:树套树,外层是一棵线段树,每个节点下有一棵平衡树(平衡树记录ls,rs,因此记录根节点就可以遍历整棵树),先不考虑空间问题,ask(l,r)可以分成多个线段树区间,每个区间下有平衡树可以查询排名,1&3-5操

【分块】bzoj3196 Tyvj 1730 二逼平衡树

分块 或 树套树. 在每个块中维护一个有序表,查询时各种二分,全都是分块的经典操作,就不详细说了. 块的大小定为sqrt(n*log2(n))比较快. 1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 int sum,sz,l[400],r[400],num[51001],a[51001],b[5100

【函数式权值分块】【分块】bzoj3196 Tyvj 1730 二逼平衡树

#include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define N 50001 #define SQRT 227 int n,m,xs[N],ys[N],ks[N],op[N],en,ma[100001],en2,a[100001]; int num[N],l[SQRT],r[SQRT],sumv[SQRT],sum=1;//分块 int num2[100001],l2[

【带修莫队】【权值分块】bzoj3196 Tyvj 1730 二逼平衡树

这题用了三种算法写: 分块+二分:O(n*sqrt(n*log(n)) 函数式权值分块:O(n*sqrt(n)) 带修莫队+权值分块:O(n5/3) 结果……复杂度越高的实际上跑得越快……最后这个竟然进第一页了…… #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int f,C; inline void R(int &