P3380 【模板】二逼平衡樹(樹套樹)

Tuilot發表於2020-11-17

排名,修改,前驅和後繼通過平衡樹都很好實現,查詢排名為k的值不是很好實現,因為這個區間可能線上段樹的多個區間內,就需要在多棵平衡樹中找,合併也不太現實,換個思路:二分值,找到排名小於k的最大值,然後在對它求一個後繼就好了。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cstdlib>

using namespace std;
typedef long long ll;
const int inf=2147483647;
const int N=50010;

int n,m,a[N];


struct Treap
{
    #define ls tr[rt].l
    #define rs tr[rt].r
    struct node
    {
        int l,r,sz,val,key;
    }tr[N<<5];
    int cnt=0;
    int newnode(int val)
    {
        tr[++cnt].val=val;
        tr[cnt].key=rand();
        tr[cnt].sz=1;
        return cnt;
    }
    void pushup(int rt){ tr[rt].sz=tr[ls].sz+tr[rs].sz+1; }
    void split(int rt,int val,int &x,int &y)
    {
        if(!rt) 
        {
            x=y=0;
            return ;
        }
        if(tr[rt].val<=val)
        {
            x=rt;
            split(tr[rt].r,val,tr[x].r,y);
            pushup(x);
            return ;
        }
        y=rt;
        split(tr[rt].l,val,x,tr[rt].l);
        pushup(y);
    }
    int merge(int x,int y)
    {
        if(!x||!y) return x+y;
        if(tr[x].key<=tr[y].key)
        {
            tr[x].r=merge(tr[x].r,y);
            pushup(x);
            return x;
        }
        tr[y].l=merge(x,tr[y].l);
        pushup(y);
        return y;
    }
    int x,y,z;
    void insert(int &rt,int val)
    {
        split(rt,val,x,y);
        rt=merge(merge(x,newnode(val)),y);
    }
    void del(int &rt,int val)
    {
        split(rt,val,x,z);
        split(x,val-1,x,y);
        rt=merge(merge(x,merge(tr[y].l,tr[y].r)),z);
    }
    int getrank(int &rt,int val)
    {
        split(rt,val-1,x,y);
        int rank=tr[x].sz;
        rt=merge(x,y);
        return rank;
    }
    int getpre(int &rt,int val)
    {
        split(rt,val-1,x,y);
        if(!x)
        {
            rt=merge(x,y);
            return -inf;
        }
        int pre=x;
        while(tr[pre].r)
        {
            pre=tr[pre].r;
        }
        rt=merge(x,y);
        return tr[pre].val;
    }
    int getnxt(int &rt,int val)
    {
        split(rt,val,x,y);
        if(!y)
        {
            rt=merge(x,y);
            return inf;
        }
        int nxt=y;
        while(tr[nxt].l)
        {
            nxt=tr[nxt].l;
        }
        rt=merge(x,y);
        return tr[nxt].val;
    }
}treap;

struct seg
{
    struct Node
    {
        int l,r;
        int root;
    }tr[N<<2];
    #define ls rt<<1
    #define rs rt<<1|1
    void build(int rt,int l,int r)
    {
        for(int i=l;i<=r;++i)
        {
            treap.insert(tr[rt].root,a[i]);
        }
        tr[rt].l=l;tr[rt].r=r;
        if(l==r) return ;
        int mid=l+r>>1;
        build(rt<<1,l,mid);
        build(rt<<1|1,mid+1,r);
    }
    int getrank(int rt,int l,int r,int k)
    {
        if(tr[rt].l>=l&&tr[rt].r<=r) return treap.getrank(tr[rt].root,k);
        int mid=tr[rt].l+tr[rt].r>>1;
        int rank=0;
        if(l<=mid) rank+=getrank(ls,l,r,k);
        if(r>mid) rank+=getrank(rs,l,r,k);
        return rank;
    }
    int getnxt(int rt,int l,int r,int val)
    {
        if(tr[rt].l>=l&&tr[rt].r<=r) return treap.getnxt(tr[rt].root,val);
        int nxt=inf;
        int mid=tr[rt].l+tr[rt].r>>1;
        if(l<=mid) nxt=min(nxt,getnxt(ls,l,r,val));
        if(r>mid) nxt=min(nxt,getnxt(rs,l,r,val));
        return nxt;
    }
    int getpre(int rt,int l,int r,int val)
    {
        if(tr[rt].l>=l&&tr[rt].r<=r) return treap.getpre(tr[rt].root,val);
        int pre=-inf;
        int mid=tr[rt].l+tr[rt].r>>1;
        if(l<=mid) pre=max(pre,getpre(ls,l,r,val));
        if(r>mid) pre=max(pre,getpre(rs,l,r,val));
        return pre;
    }
    int getnum(int x,int y,int k)
    {
        int l=0,r=1e8;
        while(l<r)
        {
            int mid=l+r>>1;
            if(getrank(1,x,y,mid)<k) l=mid+1;
            else r=mid;
        }
        return getpre(1,x,y,l);  
    }
    void modify(int rt,int x,int val)
    {
        treap.del(tr[rt].root,a[x]);
        treap.insert(tr[rt].root,val);
        if(tr[rt].l==tr[rt].r) return ;
        int mid=tr[rt].l+tr[rt].r>>1;
        if(x<=mid) modify(ls,x,val);
        else modify(rs,x,val);
    }
}tree;

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) scanf("%d",a+i);
    tree.build(1,1,n);
    while(m--)
    {
        int op,l,r,k;
        scanf("%d",&op);
        if(op==3)
        {
            scanf("%d%d",&l,&r);
            tree.modify(1,l,r);
            a[l]=r;
        }
        else
        {
            scanf("%d%d%d",&l,&r,&k);
            if(op==1) printf("%d\n",tree.getrank(1,l,r,k)+1);
            else if(op==2) printf("%d\n",tree.getnum(l,r,k));
            else if(op==5) printf("%d\n",tree.getnxt(1,l,r,k));
            else printf("%d\n",tree.getpre(1,l,r,k));
        }    
    }
    return 0;
}

相關文章