BZOJ 1208: [HNOI2004]宠物收养所
题目概述:
有一家宠物收养所,提供两种服务:收养主人遗弃的宠物和让新主人领养宠物.
宠物收养所中总是会有两种情况发生:遗弃宠物过多和领养宠物人过多.
1.遗弃宠物多时,若来一个领养人,领养最接近要求的宠物,若有多只,优先选择小的.
2.领养人多时,若来一只宠物,领养要求最接近的领养,若有多人,优先选择小的.
求领养的宠物的人的不满意度之和,不满意度为领养要求和宠物特点值的差值绝对值.
题目分析:
(又是一道Treap练手题,能一次AC,开心)
结点要么是宠物,要么是人,且在同一时刻仅有一种结点.
所以可以用一个变量state记录Treap当前结点种类.
相同,则插入;不同,则先找前驱或者后继,再删除结点.
需要注意结点为空时,选择插入结点.
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MOD=1000000;
const ll INF=(1ll<<60);
const int maxn=80000+10;
#define lc ch[u][0]
#define rc ch[u][1]
ll key[maxn];
int state,root,id;//state判断结点种类
int ch[maxn][2],rnd[maxn];
void rotate(int& u,int d)
{
int v=ch[u][d^1];
ch[u][d^1]=ch[v][d];
ch[v][d]=u;u=v;
}
void insert(int& u,int val)
{
if(!u) {
u=++id;
rc=lc=0;
key[u]=val;
rnd[u]=rand();
return ;
}
int d=val>key[u];
insert(ch[u][d],val);
if(rnd[u]>rnd[ch[u][d]]) rotate(u,d^1);
}
bool remove(int& u,int val)
{
if(!u) return false;
if(val==key[u]) {
if(!lc||!rc) return u=lc?lc:rc,true;
if(rnd[lc]>rnd[rc]) rotate(u,0);
else rotate(u,1);
return remove(u,val);
}
int d=val>key[u];
return remove(ch[u][d],val);
}
ll find_pre(int val)
{
int u=root;
ll pre=-INF;
while(u) {
if(val>key[u]) pre=key[u],u=rc;
else u=lc;
}
return pre;
}
ll find_nxt(int val)
{
int u=root;
ll nxt=INF;
while(u) {
if(val<key[u]) nxt=key[u],u=lc;
else u=rc;
}
return nxt;
}
int query(int val)
{
ll pre=find_pre(val);
ll nxt=find_nxt(val);
if(nxt-val<val-pre) return remove(root,nxt),(nxt-val)%MOD;
else return remove(root,pre),(val-pre)%MOD;
}
int main()
{
int n,a,b,ans=0;
scanf("%d",&n);
while(n--) {
scanf("%d%d",&a,&b);
if(!root||a==state) insert(root,b),state=a;
else (ans+=query(b))%=MOD;
}
printf("%d\n",ans);
return 0;
}