洛谷 P2286 [HNOI2004]宠物收养场

洛谷 P2286 [HNOI2004]宠物收养场

Description

  • 凡凡开了一间宠物收养场。收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物。

    每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希望领养的宠物的特点值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

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

Output

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

Sample Input

5                  

0 2                      

0 4                         

1 3

1 2

1 5

Sample Output

3

注:abs(3-2) + abs(2-4)=3,

最后一个领养者没有宠物可以领养。

题解:

  • 这是我写过的第一个应用Treap的题目,比较经典,需要反复推敲。
  • 本题思路就是按题意模拟,很简单。但是找离某个权值最近的权值,就是找那个权值的前驱后继啊!所以可以开两个Treap。一个记录主人,一个记录宠物。每来一个主人就在宠物Treap中找前驱和后继中最优的那个,然后删掉它;每来一个宠物就在主人Treap中找前驱和后继中最优的那个,然后删掉它。如果来一个主人,宠物Treap中是空的话,将主人添加到主人Treap中;宠物同理。这样即可解决问题。
  • 但是通过观察发现,只需要开一棵Treap就好。因为不是宠物Treap是空的就是主人Treap是空的,换句话说,任意时刻总有一个Treap是空的。所以我们就可以记录当前的Treap是宠物Treap还是主人Treap,然后更新、删除或添加即可。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#define N 80005
#define mod 1000000
#define LL long long
using namespace std;

struct T {LL val, dat, l, r, cnt;} t[N];
LL n, tim1, tim2, ans, tot, root, inf = 2147483648 + 1;

LL New(LL val)
{
    t[++tot].val = val, t[tot].dat = rand();
    t[tot].cnt = 1;
    return tot;
}

void zig(LL &y)
{
    LL x = t[y].l;
    t[y].l = t[x].r, t[x].r = y, y = x;
}

void zag(LL &x)
{
    LL y = t[x].r;
    t[x].r = t[y].l, t[y].l = x, x = y;
}

void insert(LL &p, LL val)
{
    if(!p) {p = New(val); return;}
    if(val == t[p].val) {t[p].cnt++; return;}
    if(val < t[p].val)
    {
        insert(t[p].l, val);
        if(t[t[p].l].dat > t[p].dat) zig(p);
    }
    else
    {
        insert(t[p].r, val);
        if(t[t[p].r].dat > t[p].dat) zag(p); 
    }
}

LL nextPre(LL val, LL tag)
{
    LL ans = tag == 0 ? 2 : 1, p = root;
    while(p)
    {
        if(val == t[p].val)
        {
            if(!tag && t[p].l)
            {
                p = t[p].l;
                while(t[p].r) p = t[p].r;
                ans = p; break;
            }
            else if(!tag) break;
            if(tag && t[p].r)
            {
                p = t[p].r;
                while(t[p].l) p = t[p].l;
                ans = p; break;
            }
            else if(tag) break;
        }
        if(!tag && t[p].val < val && t[p].val > t[ans].val) ans = p;
        if(tag && t[p].val > val && t[p].val < t[ans].val) ans = p;
        p = val < t[p].val ? t[p].l : t[p].r;
    }
    return t[ans].val;
}

void erase(LL &p, LL val)
{
    if(!p) return;
    if(val == t[p].val)
    {
        if(t[p].cnt > 1) {t[p].cnt--; return;}
        if(t[p].l || t[p].r)
        {
            if(!t[p].r || t[t[p].l].dat > t[t[p].r].dat)
                zig(p), erase(t[p].r, val);
            else
                zag(p), erase(t[p].l, val);
        }
        else p = 0;
        return;
    }
    val < t[p].val ? erase(t[p].l, val) : erase(t[p].r, val);
}

int main()
{
    New(inf), New(-inf), t[1].l = 2, root = 1;
    cin >> n;
    for(LL i = 1; i <= n; i++)
    {
        LL a, b;
        scanf("%lld%lld", &a, &b);
        if(!a)
        {
            tim1++; 
            if(!tim2) insert(root, b);
            else
            {
                LL v1 = nextPre(b, 0), v2 = nextPre(b, 1);
                if(abs(v1 - b) < abs(v2 - b))
                {
                    ans += abs(v1 - b), ans %= mod;
                    erase(root, v1);
                }
                else if(abs(v1 - b) == abs(v2 - b))
                {
                    ans += abs(v1 - b), ans %= mod;
                    erase(root, v1);
                }
                else
                {
                    ans += abs(v2 - b), ans %= mod;
                    erase(root, v2);
                }
                tim1--, tim2--;
            }
        }
        else
        {
            tim2++;
            if(!tim1) insert(root, b);
            else
            {
                LL v1 = nextPre(b, 0), v2 = nextPre(b, 1);
                if(abs(v1 - b) < abs(v2 - b))
                {
                    ans += abs(v1 - b), ans %= mod;
                    erase(root, v1);
                }
                else if(abs(v1 - b) == abs(v2 - b))
                {
                    ans += abs(v1 - b), ans %= mod;
                    erase(root, v1);
                }
                else
                {
                    ans += abs(v2 - b), ans %= mod;
                    erase(root, v2);
                }
                tim1--, tim2--;
            }
        }
    }
    cout << ans;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/BigYellowDog/p/11267153.html
今日推荐