[HNOI2004]宠物收养所

时间:2022-12-16 13:50:13

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

任务描述
你得到了一年当中,领养者和被收养宠物到来收养所的情况,希望你计算所有收养了宠物的领养者的不满意程度的总和。这一年初始时,收养所里面既没有宠物,也没有领养者。

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

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

Sample Input
5
0 2
0 4
1 3
1 2
1 5

Sample Output
3
|32|+|24|=3 ,最后一个领养者没有宠物可以领养)

HINT

Source

思路
这道题就是一道SBT水题啊,对于宠物和领养者可以共用一棵树,只要开一个变量记录树中存放的是宠物还是领养者就可以了。

代码

#include <cstdio>
#include <iostream>

const int maxn=200000;
const int mo=1000000;

int ans,k;

struct splay_tree
{
  int son[2][maxn+10],fa[maxn+10],tot,val[maxn+10],root;

  inline int t(int x)
  {
    return son[1][fa[x]]==x;
  }

  inline int rotate(int x)
  {
    int f=fa[x],k=t(x);
    if(fa[f])
      {
        son[t(f)][fa[f]]=x;
      }
    fa[x]=fa[f];
    son[k][f]=son[!k][x];
    if(son[k][f])
      {
        fa[son[k][f]]=f;
      }
    son[!k][x]=f;
    fa[f]=x;
    return 0;
  }

  inline int splay(int x,int c)
  {
    while(fa[x]!=c)
      {
        int f=fa[x];
        if(fa[f]==c)
          {
            rotate(x);
          }
        else if(t(x)==t(f))
          {
            rotate(f);
            rotate(x);
          }
        else
          {
            rotate(x);
            rotate(x);
          }
      }
    if(!c)
      {
        root=x;
      }
    return 0;
  }

  inline int ins(int x)
  {
    ++tot;
    val[tot]=x;
    if(!root)
      {
        root=tot;
        fa[tot]=0;
        return 0;
      }
    int now=root;
    while(now)
      {
        int k=(val[now]<x);
        if(!son[k][now])
          {
            son[k][now]=tot;
            fa[tot]=now;
            splay(tot,0);
            break;
          }
        now=son[k][now];
      }
    return 0;
  }

  inline int pre(int x)
  {
    splay(x,0);
    int now=son[0][x];
    while(son[1][now])
      {
        now=son[1][now];
      }
    return now;
  }

  inline int nex(int x)
  {
    splay(x,0);
    int now=son[1][x];
    while(son[0][now])
      {
        now=son[0][now];
      }
    return now;
  }

  inline int del(int x)
  {
    int p=pre(x);
    if(!p)
      {
        root=son[1][x];
        fa[son[1][x]]=0;
        return 0;
      }
    splay(p,x);
    root=p;
    if(son[1][x])
      {
        fa[son[1][x]]=p;
      }
    son[1][p]=son[1][x];
    son[0][x]=son[1][x]=fa[x]=0;
    fa[p]=0;
    return 0;
  }

  inline int calc(int x,int kind)
  {
    if(!root)
      {
        ins(x);
        k=kind;
        return 0;
      }
    ins(x);
    if(k!=kind)
      {
        int p=pre(tot),n=nex(tot);
        if(!p)
          {
            ans+=val[n]-x;
            del(n);
          }
        else if(!n)
          {
            ans+=x-val[p];
            del(p);
          }
        else if(x-val[p]<=val[n]-x)
          {
            ans+=x-val[p];
            del(p);
          }
        else
          {
            ans+=val[n]-x;
            del(n);
          }
        ans%=mo;
        del(tot);
      }
    return 0;
  }
};

splay_tree st;
int n;

int main()
{
  scanf("%d",&n);
  while(n--)
    {
      int a,b;
      scanf("%d%d",&a,&b);
      st.calc(b,a);
    }
  printf("%d\n",ans);
  return 0;
}