[BZOJ1208][HNOI2004]宠物收养所(平衡树splay)

题目描述

传送门

题解

很裸的平衡树。
注意一下宠物的值和领养人的值相同的情况,这个时候不应该直接查前驱和后继。
BZOJ不能调用cmath不知道为什么。

代码

#include
#include
#include
#include 
using namespace std;
#define LL long long

const int max_n=8e4+5;
const int p=1e6;

int n,a,b;
int L,R,ty;
int root,sz;
long long ans;
int f[max_n],ch[max_n][2],h[max_n],size[max_n],cnt[max_n],key[max_n];

inline void clear(int x){
    f[x]=ch[x][1]=ch[x][0]=size[x]=cnt[x]=key[x]=0;
}

inline bool get(int x){
    return ch[ f[x] ][1]==x;
}

inline void update(int x){
    if (x){
        size[x]=cnt[x];
        if (ch[x][0]) size[x]+=size[ ch[x][0] ];
        if (ch[x][1]) size[x]+=size[ ch[x][1] ];
    }
}

inline void rotate(int x){
    int old=f[x],oldf=f[old],which=get(x);

    ch[old][which]=ch[x][which^1];
    f[ ch[old][which] ]=old;

    ch[x][which^1]=old;
    f[old]=x;

    f[x]=oldf;
    if (oldf)
      ch[oldf][ ch[oldf][1]==old ]=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==0){
        root=++sz;
        f[sz]=ch[sz][0]=ch[sz][1]=0;
        size[sz]=cnt[sz]=1;
        key[sz]=x;
        return;
    }

    int now=root,fa=0;

    while (1){
        if (x==key[now]){
            cnt[now]++;
            update(now);
            splay(now);
            break;
        }

        fa=now;
        now=ch[now][ key[now]if (now==0){
            ++sz;
            f[sz]=fa;
            ch[sz][0]=ch[sz][1]=0;
            size[sz]=cnt[sz]=1;
            key[sz]=x;
            ch[fa][ key[fa]break;
        }
    }
}

inline int find(int x){
    int now=root,ans=0;

    while (1){
        if (x0];

        else{
            if (ch[now][0])
              ans+=size[ ch[now][0] ];
            if (x==key[now]){
                splay(now);
                return ans+1;
            }
            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){
    int whatever=find(x);

    if (cnt[root]>1){
        cnt[root]--;
        update(root);
        return;
    }

    if (!ch[root][0]&&!ch[root][1]){
        clear(root);
        root=0;
        return;
    }

    if (!ch[root][0]){
        int oldroot=root;
        root=ch[oldroot][1];
        f[root]=0;
        clear(oldroot);
        return;
    }

    if (!ch[root][1]){
        int oldroot=root;
        root=ch[oldroot][0];
        f[root]=0;
        clear(oldroot);
        return;
    }

    int leftbig=pre(),oldroot=root;
    splay(leftbig);

    ch[root][1]=ch[oldroot][1];
    f[ ch[root][1] ]=root;

    clear(oldroot);
    update(root);
}

int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;++i){
        scanf("%d%d",&a,&b);
        if (root==0){
            ty=a;
            insert(b);
            continue;
        }
        if (ty==a)
          insert(b);
        else{
            insert(b);
            if (cnt[root]>1){
                del(b);
                del(b);
                continue;
            }
            L=key[pre()];
            R=key[next()];
            del(b);
            if (L==0){
                int k;
                if (R-b>0) k=R-b;
                else k=b-R;
                ans=(LL)((ans+k)%p);
                del(R);
                continue;
            }
            if (R==0){
                int k;
                if (L-b>0) k=L-b;
                else k=b-L;
                ans=(LL)((ans+k)%p);
                del(L);
                continue;
            }

            int x,y;
            if (L-b>0) x=L-b;
            else x=b-L;
            if (R-b>0) y=R-b;
            else y=b-R;

            if (x<=y){
                int k=x;
                ans=(LL)((ans+k)%p);
                del(L);
            }
            else{
                int k=y;
                ans=(LL)((ans+k)%p);
                del(R);
            }
        }
    }
    printf("%lld\n",ans);
}

总结

抵制手残。

你可能感兴趣的:(题解,平衡树,省选)