bzoj 1208 宠物收养所 Splay入门

Splay伸展树,十分强大的数据结构,学习了好几天,可是做题还是很难独立敲出来QAQ
感谢:http://blog.csdn.net/crazy_ac/article/details/8034264 此篇文章的作者,代码风格我感觉灰常好!
等我熟练掌握了,我也写篇总结~~

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1208
题意:

中文题面,有宠物和人,每个单位都有一个与其他单位不同的值(正),如果现在有宠物,来了一个人,人取走和他的值最接近的宠物(如果有两个选值小的),如果现在有人,来了一个宠物,和它值最接近的人(如果有两个选值小的)取走它.求每次带宠物走两个单位的值的差的绝对值的总和.

分析:

平衡树入门题,用Splay写了
人和宠物其实是一样的,建立一颗树即可,如果树上节点是人,那么来一个宠物,就找这个值得前驱节点和后继节点,看一下哪个节点的值接近,那么求和,然后把接近的节点删掉,可以旋转到根,然后再删。

代码:

#include<cstdio>
#include<cstdlib>
const int mod =1000000;
const int inf  = ~0u>>2;
#define L ch[x][0]
#define R ch[x][1]
#define KT (ch[ ch[rt][1] ][0])
const int maxn = 1e6+9;
int lim;
struct SplayTree {
    int sz[maxn];
    int ch[maxn][2];
    int pre[maxn];
    int rt,top;
    inline void up(int x) {
        sz[x]  = cnt[x]  + sz[ L ] + sz[ R ];
    }
    inline void Rotate(int x,int f) {
        int y=pre[x];
        ch[y][!f] = ch[x][f];
        pre[ ch[x][f] ] = y;
        pre[x] = pre[y];
        if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] =x;
        ch[x][f] = y;
        pre[y] = x;
        up(y);
    }
    inline void Splay(int x,int goal) { //将x旋转到goal的下面
        while(pre[x] != goal) {
            if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][0] == x);
            else   {
                int y=pre[x],z=pre[y];
                int f = (ch[z][0]==y);
                if(ch[y][f] == x) Rotate(x,!f),Rotate(x,f);
                else Rotate(y,f),Rotate(x,f);
            }
        }
        up(x);
        if(goal==0) rt=x;
    }
    inline void RTO(int k,int goal) { //将第k位数旋转到goal的下面
        int x=rt;
        while(sz[ L ] != k-1) {
            if(k < sz[ L ]+1) x=L;
            else {
                k-=(sz[ L ]+1);
                x = R;
            }
        }
        Splay(x,goal);
    }
    inline void vist(int x) {
        if(x) {
            printf("结点%2d : 左儿子  %2d   右儿子  %2d   val:%2d sz=%d  cnt:%d\n",x,L,R,val[x],sz[x],cnt[x]);
            vist(L);
            vist(R);
        }
    }
    void debug() {
        puts("");
        vist(rt);
        puts("");
    }
    inline void Newnode(int &x,int c,int f) {
        x=++top;
        L = R = 0;
        pre[x] = f;
        sz[x]=1;
        cnt[x]=1;
        val[x] = c;
    }
    inline void init() {
        ans=0;
        type=-1;
        ch[0][0]=ch[0][1]=pre[0]=sz[0]=0;
        rt=top=0;
        cnt[0]=0;
        Newnode(rt,-inf,0);
        Newnode(ch[rt][1],inf,rt);
        sz[rt]=2;
    }
    inline void Insert(int &x,int key,int f) {
        if(!x) {
            Newnode(x,key,f);
            Splay(x,0);//注意插入完成后splay
            return ;
        }
        if(key==val[x]) {
            cnt[x]++;
            sz[x]++;
            Splay(x,0);//注意插入完成后splay
            return ;
        } else if(key<val[x]) {
            Insert(L,key,x);
        } else {
            Insert(R,key,x);
        }
        up(x);
    }
    void Del_root() { //删除根节点
        int t=rt;
        if(ch[rt][1]) {
            rt=ch[rt][1];
            RTO(1,0);
            ch[rt][0]=ch[t][0];
            if(ch[rt][0]) pre[ch[rt][0]]=rt;
        } else rt=ch[rt][0];
        pre[rt]=0;
        up(rt);
    }
    void findpre(int x,int key,int &ans) { //找前驱节点
        if(!x)  return ;
        if(val[x] <= key) {
            ans=x;
            findpre(R,key,ans);
        } else
            findpre(L,key,ans);
    }
    void findsucc(int x,int key,int &ans) { //找后继节点
        if(!x) return ;
        if(val[x]>=key) {
            ans=x;
            findsucc(L,key,ans);
        } else
            findsucc(R,key,ans);
    }


    void solve() {
        int a,b,x,y;
        scanf("%d%d",&a,&b);
        if(a==type||sz[rt]==2) {
            Insert(rt,b,0);
            type=a;
        } else {
            findpre(rt,b,x);
            findsucc(rt,b,y);
            if(abs(val[x]-b)<=abs(val[y]-b)) {
                ans+=abs(val[x]-b);
                ans%=mod;
                Splay(x,0);
                Del_root();
            } else {
                ans+=abs(val[y]-b);
                ans%=mod;
                Splay(y,0);
                Del_root();
            }
        }
    }
    int cnt[maxn];
    int val[maxn];
    int type;
    int ans;
} spt;
//bzoj 1208
int main() {
    // freopen("f.txt","r",stdin);
    int n,op,x;
    scanf("%d",&n);
    spt.init();
    while(n--)spt.solve();
    printf("%d\n",spt.ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值