【洛谷P2286】[HNOI2004]宠物收养场 --- Splay

题目描述

凡凡开了一间宠物收养场。收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物。
每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希望领养的宠物的特点值a(a是一个正整数,a<2^31),而他也给每个处在收养场的宠物一个特点值。这样他就能够很方便的处理整个领养宠物的过程了,宠物收养场总是会有两种情况发生:被遗弃的宠物过多或者是想要收养宠物的人太多,而宠物太少。
被遗弃的宠物过多时,假若到来一个领养者,这个领养者希望领养的宠物的特点值为a,那么它将会领养一只目前未被领养的宠物中特点值最接近a的一只宠物。(任何两只宠物的特点值都不可能是相同的,任何两个领养者的希望领养宠物的特点值也不可能是一样的)如果有两只满足要求的宠物,即存在两只宠物他们的特点值分别为a-b和a+b,那么领养者将会领养特点值为a-b的那只宠物。
收养宠物的人过多,假若到来一只被收养的宠物,那么哪个领养者能够领养它呢?能够领养它的领养者,是那个希望被领养宠物的特点值最接近该宠物特点值的领养者,如果该宠物的特点值为a,存在两个领养者他们希望领养宠物的特点值分别为a-b和a+b,那么特点值为a-b的那个领养者将成功领养该宠物。
一个领养者领养了一个特点值为a的宠物,而它本身希望领养的宠物的特点值为b,那么这个领养者的不满意程度为abs(a-b)。
你得到了一年当中,领养者和被收养宠物到来收养所的情况,请你计算所有收养了宠物的领养者的不满意程度的总和。这一年初始时,收养所里面既没有宠物,也没有领养者。

输入
从文件input.txt中读入数据。文件的第一行为一个正整数n,n<=80000,表示一年当中来到收养场的宠物和领养者的总数。接下来的n行,按到来时间的先后顺序描述了一年当中来到收养场的宠物和领养者的情况。每行有两个正整数a, b,其中a=0表示宠物,a=1表示领养者,b表示宠物的特点值或是领养者希望领养宠物的特点值。(同一时间呆在收养所中的,要么全是宠物,要么全是领养者,这些宠物和领养者的个数不会超过10000个)

输出
输出文件output.txt中仅有一个正整数,表示一年当中所有收养了宠物的领养者的不满意程度的总和mod 1000000以后的结果。

样例输入
5 0 2 0 4 1 3 1 2 1 5

样例输出
3

提示
abs(3-2) + abs(2-4)=3,
最后一个领养者没有宠物可以领养。

分析

  • 涉及操作:
    1. 前驱 / 后继
    2. 插入 / 删除
  • 注意点
    1. 不一定要开两棵树,只需要判断一下当前是 宠物\主人\空 就行了
    2. 要查找的数不一定是Splay中的元素。
    3. 注意边界情况(或者加入两个节点-INF, INF)

代码

#include <cstdio>
#include <cstdlib>

#define IL inline
#define mo 1000000

using namespace std;

IL int read()
{
    int k = 1, sum = 0;
    char c = getchar();
    for(; '0' > c || c > '9'; c = getchar())
    if(c == '-') k = -1;
    for(; '0' <= c && c <= '9'; c = getchar())
        sum = sum * 10 + c - '0';
    return sum * k;
}

struct node
{
    node *father;
    node *son[2];
    int val;
    int size;
    bool kind;

    IL node(int v = 0, bool k = 0, node *f = 0)
    {
        val = v;
        kind = k;
        father = f;
        son[0] = son[1] = 0;
        size = 1;
    } 
};
node *root, *stk[80005];
int top;
long long ans;

IL bool son(node *f, node *p)
{
    return f ? (f->son[1] == p) : -1;
}

IL int size(node *p)
{
    return p ? p->size : 0;
}

IL void updata(node *p)
{
    p->size = size(p->son[0]) + size(p->son[1]) + 1;
}

IL void connect(node *f, node *p, bool k)
{
    if(!f) root = p; else  f->son[k] = p;
    if(p) p->father = f;
}

IL void rotate(node *p)
{
    node *f = p->father, *g = f->father;
    bool x = son(f, p), y = !x;

    connect(f, p->son[y], x);
    connect(g, p, son(g, f));
    connect(p, f, y);

    updata(f);
}

IL void splay(node *p, node *q)
{
    for(node *f, *g; p->father != q;)
    {
        f = p->father;
        g = f->father;
        if(g == q) rotate(p); else
        if(son(g, f) ^ son(f, p))
            rotate(p), rotate(p);
        else
            rotate(f), rotate(p);
    }
    updata(p);
}

IL node *newnode(int val, int k, node *f)
{
    if(!top) return new node(val, k, f);
    stk[top]->son[0] = stk[top]->son[1] = 0;
    stk[top]->father = f;
    stk[top]->size = 1;
    stk[top]->val = val;
    stk[top]->kind = k;
    return stk[top --];
}

IL node *freenode(node *p)
{
    stk[++ top] = p;
}

IL node *find_pre(node *p)
{
    if(p != root) splay(p, 0);
    if(!p->son[0]) return p;
    for(p = p->son[0]; p->son[1]; p = p->son[1]);
    return p;
}

IL void insert(int val,int k)
{
    if(!root) root = newnode(val, k, 0);

    for(node *p = root; p; p = p->son[val > p->val])
    {
        if(val == p->val)
        {
            splay(p, 0);
            return ;
        }
        if(!p->son[val > p->val])
            p->son[val > p->val] = newnode(val, k, p);
    }
}

IL void earse(node *p)
{
    splay(p, 0);
    if(!(p->son[0]) || !(p->son[1]))
    {
        bool x = (p->son[0]) ? 0 : 1;
        freenode(p);
        root = p->son[x];
        if(root) root->father = 0;
    }else
    {
        freenode(p);
        node *t = find_pre(p);
        splay(t, p);
        root = t;
        if(root->father) root->father = 0;
        connect(t, p->son[1], 1);
    }
}

IL node *find_l(int val)
{
    node *x = 0;
    for(node *p = root; p; p = p->son[val > p->val])
    if(p->val <= val)
    {
        x = p;
    }
    if(x) splay(x, 0);
    return x;
}

IL node *find_r(int val)
{
    node *x = 0;
    for(node *p = root; p; p = p->son[val > p->val])
    if(p->val >= val)
    {
        x = p;
    }
    if(x) splay(x, 0);
    return x;
}

int main()
{
    int n = read();
    node *p1, *p2;
    for(int x, y; n; --n)
    {
        x = read();
        y = read();
        if(!root || root->kind == x)
        {
            insert(y ,x);
        }else
        {
            p1 = find_l(y);
            p2 = find_r(y);

            if(p1 && (!p2 || (p2 && (y - p1->val <= p2->val - y))))
            {
                ans = (ans + y - p1->val) % mo;
                earse(p1);
            }else
            if(p2 && (!p1 || (p1 && (y - p1->val > p2->val - y))))
            {
                ans = (ans + p2->val - y) % mo;
                earse(p2);
            }
        }
    }
    printf("%lld", ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值