bzoj 3224(splay/treap)

传送门
慢的要死的splay,比别人的splay慢了至少30%。。。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1e5+2;
int ch[2][MAXN],f[MAXN],siz[MAXN],cnt[MAXN],key[MAXN];
int sz,root;
inline void clear(int x) {
    ch[0][x]=ch[1][x]=f[x]=siz[x]=cnt[x]=key[x]=0;
}
inline bool get(int x) {
    return ch[1][f[x]]==x;
}
inline void update(int x) {
    siz[x]=siz[ch[0][x]]+siz[ch[1][x]]+cnt[x];
}
inline void rotate(int x) {
    int old=f[x],oldf=f[old],which=get(x);
    ch[which][old]=ch[!which][x],f[ch[which][old]]=old,ch[!which][x]=old;
    f[old]=x,f[x]=oldf;
    if (oldf) ch[ch[1][oldf]==old][oldf]=x;
    update(old),update(x);
}
inline void splay(int x) {
    for (int fa;fa=f[x];rotate(x))
        if (f[fa]) rotate(get(x)==get(fa)?fa:x);
    root=x;
}
inline void Insert(int x) {
    if (!root) {
        ++sz;
        ch[0][sz]=ch[1][sz]=f[sz]=0,root=sz,siz[sz]=cnt[sz]=1,key[sz]=x;
        return ;
    }
    int now=root,fa=0;
    while (1) {
        if (x==key[now]) {
            ++cnt[now],update(now),update(fa),splay(now);
            break; 
        }
        fa=now;
        now=ch[key[now]<x][now];
        if (!now) {
            ++sz;
            ch[0][sz]=ch[1][sz]=0,f[sz]=fa,siz[sz]=cnt[sz]=1;
            ch[key[fa]<x][fa]=sz,key[sz]=x;
            update(fa);
            splay(sz);
            break;
        }
    }
}
inline int rank(int x) {
    int now=root,ans=0;
    while (1) {
        if (x<key[now]) now=ch[0][now];
        else {
            ans+=(ch[0][now]?siz[ch[0][now]]:0);
            if (x==key[now]) {
                splay(now);
                return ans+1;
            }
            ans+=cnt[now];
            now=ch[1][now];
        }
    }
}
inline int find(int x) {
    int now=root;
    while (1) {
        if (ch[0][now]&&x<=siz[ch[0][now]]) now=ch[0][now];
        else {
            int temp=(ch[0][now]?siz[ch[0][now]]:0)+cnt[now];
            if (x<=temp) return key[now];
            x-=temp;now=ch[1][now];
        }
    }
}
inline int pre() {
    int now=ch[0][root];
    while (ch[1][now]) now=ch[1][now];
    return now;
}
inline int nxt() {
    int now=ch[1][root];
    while (ch[0][now]) now=ch[0][now];
    return now;
}
inline void del(int x) {
    int must=rank(x);
    if (cnt[root]>1) {--cnt[root];update(root);return ;}
    if (!ch[0][root]&&!ch[1][root]) {clear(root);root=0;return ;}
    if (!ch[0][root]) {
        int oldroot=root;
        root=ch[1][root],f[root]=0,clear(oldroot);
        return ;
    }
    else if (!ch[1][root]) {
        int oldroot=root;
        root=ch[0][root],f[root]=0,clear(oldroot);
        return ;
    }
    int leftbig=pre(),oldroot=root;
    splay(leftbig);
    ch[1][root]=ch[1][oldroot];
    f[ch[1][oldroot]]=root;
    clear(oldroot);
    update(root);
}
int main() {
//  freopen("bzoj 3224.in","r",stdin);
    int n,opt,x;
    scanf("%d",&n);
    for (register int i=0;i<n;++i) {
        scanf("%d%d",&opt,&x);
        switch (opt) {
            case 1:{Insert(x);break;}
            case 2:{del(x);break;}
            case 3:{printf("%d\n",rank(x));break;}
            case 4:{printf("%d\n",find(x));break;}
            case 5:{Insert(x);printf("%d\n",key[pre()]);del(x);break;}
            case 6:{Insert(x);printf("%d\n",key[nxt()]);del(x);break;}
        }
    }
    return 0;
}

treap还勉强说得过去。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
struct data{
    int l,r,v,size,rnd,w;//左/右儿子,权值,子树大小,优先级,重复计数
    data() {l=0,r=0,size=0,w=0;}
}node[100004];
int n,size,root,ans,opt,x;//x为权值
inline int randad(){
   static int seed=426;
   return seed=int(seed*48271LL%2147483647);
}
inline void update(int k) {
    node[k].size=node[node[k].l].size+node[node[k].r].size+node[k].w;
}
void rturn(int &k) {
    int t=node[k].l;
    node[k].l=node[t].r;
    node[t].r=k;
    node[t].size=node[k].size;
    update(k);
    k=t;
}
void lturn(int &k) {
    int t=node[k].r;
    node[k].r=node[t].l;
    node[t].l=k;
    node[t].size=node[k].size;
    update(k);
    k=t;
}
void insert(int &k,int x) {
    if (k==0) {
        k=++size;
        node[k].size=node[k].w=1,node[k].v=x,node[k].rnd=randad();
        return;
    }
    ++node[k].size;
    if (x==node[k].v) ++node[k].w;//当前为位,重复计数一次 
    else if (x>node[k].v) {//插入右子树 
        insert(node[k].r,x);
        if (node[node[k].r].rnd<node[k].rnd) lturn(k);
    }
    else {//插入左子树 
        insert(node[k].l,x);
        if (node[node[k].l].rnd<node[k].rnd) rturn(k);
    } 
}
void del(int &k,int x) {
    if (k==0) return; 
    if (node[k].v==x) {
        if (node[k].w>1) {--node[k].w;--node[k].size;return;}
        if (!node[k].l||!node[k].r) k=node[k].l+node[k].r;//直接让儿子代替自己 
        else if (node[node[k].l].rnd<node[node[k].r].rnd) rturn(k),del(k,x);
        else lturn(k),del(k,x);
    }
    else if (x>node[k].v) --node[k].size,del(node[k].r,x);//处理右子树
    else --node[k].size,del(node[k].l,x);//处理左子树 
}
int rank(int k,int x) {//数x排名第几 
    if (k==0) return 0;
    if (node[k].v==x)
        return node[node[k].l].size+1;
    else if (x>node[k].v)
        return node[node[k].l].size+node[k].w+rank(node[k].r,x);
    else return rank(node[k].l,x);
}
int num(int k,int x) {//排第x的是啥 
    if (k==0) return 0;
    if (x<=node[node[k].l].size) return num(node[k].l,x);
    else if (x>node[node[k].l].size+node[k].w) return num(node[k].r,x-node[node[k].l].size-node[k].w);
    else return node[k].v;
}
void pro(int k,int x) {//数x的前驱 
    if (k==0) return ;
    if (node[k].v<x) ans=k,pro(node[k].r,x); 
    else pro(node[k].l,x);
}
void sub(int k,int x) {//数x的后继 
    if (k==0) return ;
    if (node[k].v>x) ans=k,sub(node[k].l,x); 
    else sub(node[k].r,x);
}
int main() {
    scanf("%d",&n);
    for (int i=1;i<=n;++i) {
        scanf("%d%d",&opt,&x);
        switch(opt) {
            case 1:insert(root,x);break;
            case 2:del(root,x);break;
            case 3:printf("%d\n",rank(root,x));break;
            case 4:printf("%d\n",num(root,x));break;
            case 5:ans=0;pro(root,x);printf("%d\n",node[ans].v);break;
            case 6:ans=0;sub(root,x);printf("%d\n",node[ans].v);break;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值