二逼平衡树(线段树套Splay)

传送门
(update at 10.31)
我的第一次调出样例:
这里写图片描述
我就很无语了,居然会TLE
然后hzy dalao就告诉我:“我们那个板子一直都是错的!”
然后就告诉了我splay的正确姿势,然后。。。
这里写图片描述
我就问他:“这难道不是你的板子吗?”
hzy:“你写的丑。”
我:“。。。”
然后我就愉快地去大(yang)牛(qi)分站交了一发,果断AC了这题。
这里写图片描述
其实我原来用的那个splay真的有问题,常数太大,每次都要splay好几次,查前驱后继还要插入&删除,所以常数大概大了3倍左右,所以会TLE。
这个splay还是不错的。
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
inline int read(){
    int x=0;char ch=' ';int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
const int N=5e4+5;
const int inf=2147483647;
int n,m,sz;
int a[N],key[N*100],cnt[N*100],size[N*100],ch[N*100][2],f[N*100];
struct Splay{
    int root;
    inline bool get(int x){return ch[f[x]][1]==x;}
    inline void clear(int x){key[x]=cnt[x]=size[x]=f[x]=ch[x][0]=ch[x][1]=0;}
    inline void update(int x){size[x]=cnt[x]+size[ch[x][0]]+size[ch[x][1]];}
    inline void rotate(int x){
        int y=f[x],z=f[y],w=get(x),w2=get(y);
        ch[y][w]=ch[x][w^1];f[ch[y][w]]=y;
        ch[x][w^1]=y;f[y]=x;
        f[x]=z;if(z)ch[z][w2]=x;
        update(y);update(x);
    }
    inline void splay(int x){
        for(int fa=0;(fa=f[x]);rotate(x))
            if(f[fa])
                rotate((get(x)==get(fa))?fa:x);
        root=x;
    }
    inline void insert(int x){
        if(!root){key[++sz]=x;cnt[sz]=size[sz]=1;root=sz;return;}
        int now=root,fa;
        while(1){
            if(x==key[now]){cnt[now]++;update(now);splay(now);return;}
            fa=now;
            now=ch[now][x>key[now]];
            if(!now){
                ch[fa][x>key[fa]]=++sz;
                key[sz]=x;cnt[sz]=size[sz]=1;f[sz]=fa;
                update(fa);splay(sz);return;
            }
        }
    }
    inline int find(int x){
        int now=root,ans=0;
        while(1){
            if(ch[now][0]&&x<key[now]){
                now=ch[now][0];
            }
            else{
                ans+=size[ch[now][0]];
                if(x==key[now]){splay(now);return ans;}
                ans+=cnt[now];now=ch[now][1];
            }
        }
    }
    inline int find2(int x){
        int now=root,ans=0;
        while(1){
            if(ch[now][0]&&x<key[now]){
                now=ch[now][0];
            }
            else{
                ans+=size[ch[now][0]];
                if(x==key[now]){splay(now);return ans+cnt[now];}
                ans+=cnt[now];now=ch[now][1];
            }
        }
    }
    inline int pre(){
        int now=ch[root][0];
        while(ch[now][1])now=ch[now][1];
        return now;
    }
    inline int next(){
        int now=ch[root][1];
        while(ch[now][0])now=ch[now][0];
        return now;
    }
    inline void del(int x){
        find(x);
        if(cnt[root]>1){cnt[root]--;update(root);return;}
        int leftbig=pre(),oldroot=root;
        splay(leftbig);
        ch[root][1]=ch[oldroot][1];f[ch[root][1]]=root;
        clear(oldroot);update(root);
    }
    inline void print(int now){
        if(ch[now][0])print(ch[now][0]);
        cout<<key[now]<<' ';
        if(ch[now][1])print(ch[now][1]);
    }
}t[N<<2];
int L,R,x,pos,k,ans;
inline void build(int rt,int l,int r){
    t[rt].root=0;
    t[rt].insert(inf);t[rt].insert(-inf);
    for(int i=l;i<=r;i++)t[rt].insert(a[i]);
    if(l==r)return;
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
}
inline void update(int rt,int l,int r){
    t[rt].del(a[pos]);t[rt].insert(x);
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)update(rt<<1,l,mid);
    else update(rt<<1|1,mid+1,r);
}
inline void find(int rt,int l,int r){
    if(L<=l&&r<=R){t[rt].insert(x);ans+=t[rt].find(x)-1;t[rt].del(x);return;}
    int mid=(l+r)>>1;
    if(L<=mid)find(rt<<1,l,mid);
    if(mid+1<=R)find(rt<<1|1,mid+1,r);
}
inline void find2(int rt,int l,int r){
    if(L<=l&&r<=R){t[rt].insert(x);ans+=t[rt].find2(x)-2;t[rt].del(x);return;}
    int mid=(l+r)>>1;
    if(L<=mid)find2(rt<<1,l,mid);
    if(mid+1<=R)find2(rt<<1|1,mid+1,r);
}
inline int kth(){
    int l=0,r=1e8;
    while(l<r){
        x=(l+r)>>1;ans=0;find2(1,1,n);
        if(ans+1<=k)l=x+1;
        else r=x;
    }
    return r;
}
inline void pre(int rt,int l,int r){
    if(L<=l&&r<=R){t[rt].insert(x);ans=max(ans,key[t[rt].pre()]);t[rt].del(x);return;}
    int mid=(l+r)>>1;
    if(L<=mid)pre(rt<<1,l,mid);
    if(mid+1<=R)pre(rt<<1|1,mid+1,r);
}
inline void next(int rt,int l,int r){
    if(L<=l&&r<=R){t[rt].insert(x);ans=min(ans,key[t[rt].next()]);t[rt].del(x);return;}
    int mid=(l+r)>>1;
    if(L<=mid)next(rt<<1,l,mid);
    if(mid+1<=R)next(rt<<1|1,mid+1,r);
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)a[i]=read();
    build(1,1,n);
    while(m--){
        int opt=read();
        switch(opt){
            case 1:L=read();R=read();x=read();ans=0;find(1,1,n);printf("%d\n",ans+1);break;
            case 2:L=read();R=read();k=read();printf("%d\n",kth());break;
            case 3:pos=read();x=read();update(1,1,n);a[pos]=x;break;
            case 4:L=read();R=read();x=read();ans=-inf;pre(1,1,n);printf("%d\n",ans);break;
            case 5:L=read();R=read();x=read();ans=inf;next(1,1,n);printf("%d\n",ans);break;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值