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

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

前置芝士 P3369 【模板】普通平衡树

线段树套平衡树

这里写的是线段树+splay(不吸氧竟然卡过了)

对线段树的每个节点都维护一颗平衡树

每次把给定区间内

线段树上节点维护的平衡树的信息

查询一遍就好辣

$opt2$:每次二分一个答案k,蓝后用$opt1$跑,再判断偏大还是偏小

我真的要好好背背splay的各种神仙操作了TAT

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
inline int Max(int a,int b){return a>b?a:b;}
inline int Min(int a,int b){return a<b?a:b;}
void read(int &x){
    static char c=getchar();x=0;
    while(c<'0'||c>'9') c=getchar();
    while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar();
}
#define N 50005
const int inf=2147483647;
struct node{
    int ch[2],siz,v,fa;
    void clear(){ch[0]=ch[1]=v=fa=siz=0;}
}a[4000005];
int n,m,u,A[N];
queue <int> lit;
int New(){
    if(lit.empty()) return ++u;
    int p=lit.front(); lit.pop(); return p;
}
struct Splay{
    #define lc a[x].ch[0]
    #define rc a[x].ch[1]
    int rt,re;
    inline void up(int x){a[x].siz=a[lc].siz+a[rc].siz+1;}
    inline int whi(int y,int x){return a[y].ch[1]==x;}
    void turn(int x,int &k){
        int y=a[x].fa,z=a[y].fa,l=whi(y,x),r=l^1;
        if(y==k) k=x;
        else a[z].ch[whi(z,y)]=x;
        a[a[x].ch[r]].fa=y; a[y].fa=x; a[x].fa=z;
        a[y].ch[l]=a[x].ch[r]; a[x].ch[r]=y;
        up(y); up(x);
    }
    void splay(int x,int &k){
        for(;x!=k;turn(x,k)){
            int y=a[x].fa,z=a[y].fa;
            if(y!=k) turn((whi(z,y)^whi(y,x))?x:y,k);
        }
    }
    int find(int x,int k){
        while(a[lc].siz+1!=k){
            if(a[lc].siz+1>=k) x=lc;
            else k=k-a[lc].siz-1,x=rc;
        }return x;
    }
    int torank(int k){
        int x=rt,re=0,id=0;
        while(x){
            if(a[x].v==k) id=x;
            if(a[x].v>=k) x=lc;
            else re+=a[lc].siz+1,x=rc;
        }if(id) splay(id,rt);//
        return re;
    }
    void ins(int k){
        int x=rt,Fa=0;
        while(x) Fa=x,x=a[x].ch[a[x].v<=k];
        x=New(); a[x].v=k,a[x].fa=Fa;
        if(rt) a[Fa].ch[a[Fa].v<=k]=x,splay(x,rt);
        else rt=x;
    }
    void del(int k){
        int x=rt,p,tmp;
        while(a[x].v!=k) x=a[x].ch[a[x].v<=k];
        splay(x,rt); tmp=rt;
        if(lc&&rc){//
            p=find(rt,a[lc].siz); splay(p,lc),x=rt;
            a[lc].ch[1]=rc,a[rc].fa=lc;
            rt=lc,a[rt].fa=0,up(rt);
        }else if(lc) a[lc].fa=0,rt=lc;
        else if(rc) a[rc].fa=0,rt=rc;
        else rt=0;
        a[tmp].clear(); lit.push(tmp);
    }
    void Pre(int x,int k){
        if(!x) return;
        if(re<a[x].v&&a[x].v<k) re=a[x].v;
        Pre(a[x].ch[a[x].v<k],k);
    }
    void Last(int x,int k){
        if(!x) return ;
        if(k<a[x].v&&a[x].v<re) re=a[x].v;
        Last(a[x].ch[a[x].v<=k],k);
    }
    int pre(int k){re=-inf;Pre(rt,k);return re;}
    int last(int k){re=inf;Last(rt,k);return re;}
    #undef lc
    #undef rc
}s[N<<2];
struct Seg_tree{
    #define lc o<<1
    #define rc o<<1|1
    #define mid (l+r)/2
    void Ins(int o,int l,int r,int x,int v){
        s[o].ins(v);
        if(l==r) return ;
        if(x<=mid) Ins(lc,l,mid,x,v);
        else Ins(rc,mid+1,r,x,v);
    }
    int Ask1(int o,int l,int r,int x1,int x2,int v){
        if(x1<=l&&r<=x2) return s[o].torank(v);
        int re=0;
        if(x1<=mid) re+=Ask1(lc,l,mid,x1,x2,v);
        if(x2>mid) re+=Ask1(rc,mid+1,r,x1,x2,v);
        return re;
    }
    void Modi(int o,int l,int r,int x,int v1,int v2){
        s[o].del(v1); s[o].ins(v2);
        if(l==r) return ;
        if(x<=mid) Modi(lc,l,mid,x,v1,v2);
        else Modi(rc,mid+1,r,x,v1,v2);
    }
    int Ask4(int o,int l,int r,int x1,int x2,int v){
        if(x1<=l&&r<=x2) return s[o].pre(v);
        int re=-inf;
        if(x1<=mid) re=Max(re,Ask4(lc,l,mid,x1,x2,v));
        if(x2>mid) re=Max(re,Ask4(rc,mid+1,r,x1,x2,v));
        return re;
    }
    int Ask5(int o,int l,int r,int x1,int x2,int v){
        if(x1<=l&&r<=x2) return s[o].last(v);
        int re=inf;
        if(x1<=mid) re=Min(re,Ask5(lc,l,mid,x1,x2,v));
        if(x2>mid) re=Min(re,Ask5(rc,mid+1,r,x1,x2,v));
        return re;
    }
    #undef lc
    #undef rc
    #undef mid
}T;
int main(){
    read(n);read(m); register int i; int q1,q2,q3,q4;
    for(i=1;i<=n;++i) read(A[i]),T.Ins(1,1,n,i,A[i]);
    while(m--){
        read(q1);read(q2);read(q3);
        switch(q1){
            case 1:{read(q4),printf("%d\n",T.Ask1(1,1,n,q2,q3,q4)+1);break;}//排名要+1,算上自己
            case 2:{
                read(q4);
                int l=0,r=1e8;
                while(l<r){ //二分比较特殊,每次二分的mid要偏大一点
                    int mid=(l+r+1)/2;
                    if(T.Ask1(1,1,n,q2,q3,mid)<q4) l=mid;
                    else r=mid-1;
                }printf("%d\n",l);
                break;
            }
            case 3:{T.Modi(1,1,n,q2,A[q2],q3),A[q2]=q3;break;}
            case 4:{read(q4),printf("%d\n",T.Ask4(1,1,n,q2,q3,q4));break;}
            case 5:{read(q4),printf("%d\n",T.Ask5(1,1,n,q2,q3,q4));break;}
        }
    }return 0;
}

猜你喜欢

转载自www.cnblogs.com/kafuuchino/p/10590535.html