题面
思路
根据题意,每一个主人到达收养所后,如果有宠物,就会领养。同样地,宠物也是如此,只要有主人就会被领养。这样就能理解题目中 “宠物收养场总是会有两种情况发生:被遗弃的宠物过多或者是想要收养宠物的人太多,而宠物太少”。
如何找到特点值最接近的主人/宠物?找一个集合中最接近 x 的元素,自然就想到了平衡树。我在这道题使用了 Treap。最接近的 x 特征值就是 x 前驱和后继中更接近 x 的那一个。
所以我们可以开两棵 Treap,分别存储宠物的特点值和主人的特点值。再记录下当前两个 Treap 中分别有多少个元素。
每当一个宠物 x 进入,如果主人的 Treap 不为空,就在主人 Treap 中找 x 的前驱和后继,选择更接近 x 的那个(根据题意如果差值相同就选前驱),并累计不满意度总值,然后从主人 Treap 中删除这个元素。否则如果主人的 Treap 为空,就将 x 加入宠物的 Treap 中,等待下一个主人。
对应地,每当一个主人 y 进入,如果宠物的 Treap 不为空,就在宠物 Treap 中找 y 的前驱和后继,选择更接近 y 的那个,然后删除它(已经被领养了),并累计不满意度总值,然后从宠物 Treap 中删除这个元素。否则如果宠物的 Treap 为空,就将 y 加入主人的 Treap 中,等待下一个宠物。
代码
#include<bits/stdc++.h>
using namespace std;
int q;
struct treap{//封装 Treap
struct node{
long long x,y,l,r,size,cnt;
};
node s[1000001];
long long top,root;
void reset(){
top=0;
root=0;
}
void update(long long x){
s[x].size=s[s[x].l].size+s[s[x].r].size+s[x].cnt;
}
void rotr(long long &x){
long long l=s[x].l;
s[x].l=s[l].r;
s[l].r=x;
s[l].size=s[x].size;
update(x);
x=l;
}
void rotl(long long &x){
long long r=s[x].r;
s[x].r=s[r].l;
s[r].l=x;
s[r].size=s[x].size;
update(x);
x=r;
}
void add(long long &x,long long data){
if (!x){
x=++top;
s[x].x=data;
s[x].y=rand()%19260817;
s[x].cnt=1;
s[x].size=1;
s[x].l=0;
s[x].r=0;
return;
}
s[x].size++;
if (s[x].x==data){
s[x].cnt++;
}else if (data<s[x].x){
add(s[x].l,data);
if (s[x].y>s[s[x].l].y){
rotr(x);
}
}else{
add(s[x].r,data);
if (s[x].y>s[s[x].r].y){
rotl(x);
}
}
}
void del(long long &x,long long data){
if (s[x].x==data){
if (s[x].cnt>1){
s[x].cnt--;
s[x].size--;
return;
}
if (!s[x].l||!s[x].r){
x=s[x].l+s[x].r;
return;
}
if (s[s[x].l].y<s[s[x].r].y){
rotr(x);
del(x,data);
}else{
rotl(x);
del(x,data);
}
return;
}
s[x].size--;
if (data<s[x].x){
del(s[x].l,data);
}else{
del(s[x].r,data);
}
}
long long pre(long long data){
long long now=root,res=-2147483647;
while (now){
if (s[now].x<data){
res=s[now].x;
now=s[now].r;
}else{
now=s[now].l;
}
}
return res;
}
long long nxt(long long data){
long long now=root,res=2147483647;
while (now){
if (s[now].x>data){
res=s[now].x;
now=s[now].l;
}else{
now=s[now].r;
}
}
return res;
}
long long querykth(long long k){
long long now=root;
while (now){
if (s[s[now].l].size<k&&s[s[now].l].size+s[now].cnt>=k){
return s[now].x;
}
if (s[s[now].l].size>=k){
now=s[now].l;
}else{
k-=s[s[now].l].size+s[now].cnt;
now=s[now].r;
}
}
return 0;
}
long long queryrank(long long data){
long long now=root,res=0;
while (now){
if (data==s[now].x){
return res+s[s[now].l].size+1;
}
if (data<s[now].x){
now=s[now].l;
}else{
res+=s[s[now].l].size+s[now].cnt;
now=s[now].r;
}
}
return res;
}
};
long long n,ans=0;//ans 为不满意度总和
treap a,b;//存储宠物和主人特征值
long long A=0,B=0;//分别表示宠物和主人 Treap 中有多少个元素
int main(){
srand(time(0));
a.reset();
b.reset();
cin>>n;
for (int i=1;i<=n;i++){
long long x,y;
cin>>x>>y;
if (x==0){//如果是宠物
if (B>0){//如果主人 Treap 不为空(当前有正在等待的主人)
long long tar1=b.pre(y);//在主人中找前驱
long long tar2=b.nxt(y);//找后继
if (y-tar1>tar2-y){//选取更接近的那个
ans+=tar2-y;//更新不满意度
b.del(b.root,tar2);//从主人 Treap 中删除匹配到的主人
}else{
ans+=y-tar1;//同上
b.del(b.root,tar1);
}
B--;//主人 Treap 元素总和减 1
}else{//如果没有在等待的主人
A++;//宠物 Treap 元素总和加 1
a.add(a.root,y);//宠物 Treap 插入当前宠物的特征值
}
}else{
if (A>0){//同上,只是这次是主人匹配宠物
long long tar1=a.pre(y);
long long tar2=a.nxt(y);
if (y-tar1>tar2-y){
ans+=tar2-y;
a.del(a.root,tar2);
}else{
ans+=y-tar1;
a.del(a.root,tar1);
}
A--;
}else{
B++;
b.add(b.root,y);
}
}
ans%=1000000;//取模
}
cout<<ans%1000000;
}