【BZOJ1208】【HNOI2004】宠物收养所(splay)

【问题描述】

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

    n<=80000。同一时间呆在收养所中的,要么全是宠物,要么全是领养者,这些宠物和领养者的个数不会超过10000个

【分析】

    平衡树模板,都是基础操作,直接写splay了。

    由于同一时间要么全是宠物要么全是领养者,所以只要一颗树就好了。

    找前驱和后继,我不是把点旋到根。例如x的前驱,从根往下走寻找x。每次可能往左儿子走也可能往右儿子走,x的前驱即从根到x的路径中最后一次往右走的那个点。画一下图就知道了。不过这样子不见得比旋到根好就是了。- -

【代码】

    代码一向略龊。。。

/**************************************************************
    Problem: 1208
    User: N_C_Derek
    Language: C++
    Result: Accepted
    Time:184 ms
    Memory:2836 kb
****************************************************************/
 
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
int root,ifman,ans,t,n;
struct node
{
    int l,r,data,father;
}tree[100000];
void zig(int x)
{
    int p = tree[x].father;
    if (tree[p].father)
    {
        if (tree[tree[p].father].l == p)
            tree[tree[p].father].l = x;
        else
            tree[tree[p].father].r = x;
    }
    tree[x].father = tree[p].father;
    tree[p].father = x;
    tree[p].l = tree[x].r;
    if (tree[x].r) tree[tree[x].r].father = p;
    tree[x].r = p;
}
void zag(int x)
{
    int p = tree[x].father;
    if (tree[p].father)
    {
        if (tree[tree[p].father].l == p)
            tree[tree[p].father].l = x;
        else
            tree[tree[p].father].r = x;
    }
    tree[x].father = tree[p].father;
    tree[p].father = x;
    tree[p].r = tree[x].l;
    if (tree[x].l) tree[tree[x].l].father = p;
    tree[x].l = p;
}
void splay(int x)
{
    while (tree[x].father)
    {
        int j = tree[x].father;
        if (tree[j].father == 0)
        {
            if (tree[j].l == x)
                zig(x);
            else zag(x);
            break;
        }
        if (tree[tree[j].father].l == j)
        {
            if (tree[j].l == x)
                {zig(j);zig(x);}
            else
                {zag(x);zig(x);}
        }else
        {
            if (tree[j].r == x)
                {zag(j);zag(x);}
            else
                {zig(x);zag(x);}
        }
    }
    root = x;
}
void Insert(int x)
{
    if (!root)
    {
        root = ++t;
        tree[root].father = 0;
        tree[root].data = x;
        return;
    }
    int i = root;
    while (tree[i].l || tree[i].r)
    {
        if (tree[i].data > x)
            {if (!tree[i].l) break;i = tree[i].l;}
        else
            {if (!tree[i].r) break;i = tree[i].r;}
    }
    if (tree[i].data > x)
        tree[i].l = ++t;
    else tree[i].r = ++t;
    tree[t].father = i;
    tree[t].data = x;
    splay(t);
}
void get_max()
{
    int i = root;
    while (tree[i].r)
        i = tree[i].r;
    splay(i);
}
void Delete(int x)
{
    splay(x);
    if (!tree[x].l)
    {
        root = tree[x].r;
        tree[root].father = 0;
        return;
    }
    int tmp = tree[root].r;
    root = tree[root].l;
    get_max();
    tree[root].r = tmp;
    tree[tmp].father = root;
}
int find(int x)
{
    int i = root,ii = 0;
    while (i)
    {
        if (tree[i].data > x)
        {
            ii = i;i = tree[i].l;
        }else i = tree[i].r;
    }
    int j = root,jj = 0;
    while (j)
    {
        if (tree[j].data < x)
        {
            jj = j;j = tree[j].r;
        }else j = tree[j].l;
    }
    if (jj && (!ii || abs(tree[jj].data - x) <= abs(tree[ii].data - x)))
        return jj;
    else return ii;
}
int main()
{
    scanf("%d",&n);
    for (int i = 1;i <= n;i ++)
    {
        int k,x;
        scanf("%d %d",&k,&x);
        if (k == 1)
        {
            if (ifman || !root)
            {
                Insert(x);
                ifman = 1;
            }
            else
            {
                int j = find(x);
                ans = (ans + abs(tree[j].data - x)) % 1000000;
                Delete(j);
            }
        }else
        {
            if (!ifman || !root)
            {
                Insert(x);
                ifman = 0;
            } else
            {
                int j = find(x);
                ans = (ans + abs(tree[j].data - x)) % 1000000;
                Delete(j);
            }
        }
    }
    cout << ans;
}

 

posted @ 2013-01-10 19:59  N_C_Derek  阅读(268)  评论(0编辑  收藏  举报