世界真的很大
关于这道题,其实并不难,但限于我的代码能力,也足足花了40分钟,,,
description:
最近,阿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)。【任务描述】你得到了一年当中,领养者和被收养宠物到来收养所的情况,希望你计算所有收养了宠物的领养者的不满意程度的总和。这一年初始时,收养所里面既没有宠物,也没有领养者。
input:
第一行为一个正整数n,n<=80000,表示一年当中来到收养所的宠物和领养者的总数。接下来的n行,按到来时间的先后顺序描述了一年当中来到收养所的宠物和领养者的情况。每行有两个正整数a, b,其中a=0表示宠物,a=1表示领养者,b表示宠物的特点值或是领养者希望领养宠物的特点值。(同一时间呆在收养所中的,要么全是宠物,要么全是领养者,这些宠物和领养者的个数不会超过10000个)
output:
仅有一个正整数,表示一年当中所有收养了宠物的领养者的不满意程度的总和mod 1000000以后的结果。
来看一下这道题,看到什么特点值最接近啦,大也可以小也可以,而且数据范围大概在10^5级别,很明显的就是数据结构的题了。想到前驱后继的话,就是平衡树了吧。这道题用不到很高级的平衡树,基础的treap就可以了。
思路很简单,因为题目要求一段时间内宠物店里只可能有人或宠物,因为宠物多的话来个人就能领养,不会有人剩下来,反之亦然。
那我们考虑建一颗treap维护宠物店里的物种,打个标记标记宠物店里的物种是什么,如果来的物种和宠物店里的相同的话就加入treap,不一样的话就从她的前驱后继中选一个最近的算进ans然后从treap里删除,所用到的都是基本的操作。
需要注意的地方也有,比如统计前驱后继的pre和pst一开始最好预设成-1或0,然后判断的时候单独判断这种情况。因为设成正负无穷的话万一查询特别大就会在删除时错误删除以至于超过边界,RE。
完整代码:
#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
node *ch[2];
int cnt,val,key,siz;
node(int x)
{
this->val=x;
key=rand();
siz=1;cnt=1;
ch[0]=ch[1]=0;
}
int compare(int x)
{
if(x==val) return -1;
return x > val ? 1 : 0;
}
void update()
{
siz=this->cnt;
if(ch[0]!=0) siz+=ch[0]->siz;
if(ch[1]!=0) siz+=ch[1]->siz;
}
}*root=0;
int n,opt,x,pst,pre,tmp,mod=1000000,tree,num=0,ans=0;
void rot(node* &t,int d)
{
node *k=t->ch[d^1];
t->ch[d^1] = k->ch[d];
k->ch[d] = t;
t->update();
k->update();
t=k;
}
void insert(node* &t,int x)
{
if(t==0)
{
t=new node(x);
return;
}
int d = t->compare(x);
if(d==-1)
{
t->cnt++;
t->siz++;
}
else
{
t->siz++;insert(t->ch[d],x);
if(t->ch[d]->key > t->key)
rot(t,d^1);
}
t->update();
}
void del(node* &t,int x)
{
// if(!t) return ;
int d = t->compare(x);
if(d==-1)
{
node *tmp = t;
if(t->cnt > 1)
{
t->siz--;
t->cnt--;
}
else if(t->ch[0]==0)
{
t=t->ch[1];
delete tmp;
tmp=0;
}
else if(t->ch[1]==0)
{
t=t->ch[0];
delete tmp;
tmp=0;
}
else
{
int e=t->ch[0]->key > t->ch[1]->key ? 1 : 0;
rot(t,e);
del(t->ch[e],x);
}
}
else
{
t->siz--;
del(t->ch[d],x);
}
if(t!=0) t->update();//防止删空
}
void aft(node *t,int x){
if(!t) return;
int d=t->compare(x);
if(d==1||d==-1)
aft(t->ch[1],x);
else if(!d)
{
pst=t->val;
aft(t->ch[0],x);
}
}
void bef(node *t,int x){
if(!t) return;
int d=t->compare(x);
if(d==1)
{
pre=t->val;
bef(t->ch[1],x);
}
else if(d==0||d==-1)
bef(t->ch[0],x);
}
void Railgun(int x)
{
pre=-1,pst=-1;
bef(root,x),aft(root,x);
if(pre==-1)
{
ans+=pst-x;
ans%=mod;
del(root,pst);
}
else if(pst==-1)
{
ans+=x-pre;
ans%=mod;
del(root,pre);
}
else
{
if(x-pre>pst-x)
{
ans+=pst-x;
ans%=mod;
del(root,pst);
}
else
{
ans+=x-pre;
ans%=mod;
del(root,pre);
}
}
}
int main()
{
int n;
scanf("%d",&n);
tree=2;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&opt,&x);
if(!root)
{
tree=opt;
insert(root,x);
}
else if(tree==opt)
{
insert(root,x);
}
else
Railgun(x);
}
printf("%d",ans%mod);
return 0;
}
因为我也借这个契机,整理了一下treap的全部操作,正好有一道全操作的题,bzoj 3224。
description:
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
全操作模板如下:
#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
node *ch[2];
int cnt,val,key,siz;
node(int x)
{
this->val=x;
key=rand();
siz=1;cnt=1;
ch[0]=ch[1]=0;
}
int compare(int x)
{
if(x==val) return -1;
return x > val ? 1 : 0;
}
void update()
{
siz=this->cnt;
if(ch[0]!=0) siz+=ch[0]->siz;
if(ch[1]!=0) siz+=ch[1]->siz;
}
}*root=0;
int n,opt,x,pst,pre,tmp;
void rot(node* &t,int d)
{
node *k=t->ch[d^1];
t->ch[d^1] = k->ch[d];
k->ch[d] = t;
t->update();
k->update();
t=k;
}
void insert(node* &t,int x)
{
if(t==0)
{
t=new node(x);
return;
}
int d = t->compare(x);
if(d==-1)
{
t->cnt++;
t->siz++;
}
else
{
t->siz++;insert(t->ch[d],x);
if(t->ch[d]->key > t->key)
rot(t,d^1);
}
t->update();
}
void del(node* &t,int x)
{
if(!t) return ;
int d = t->compare(x);
if(d==-1)
{
node *tmp = t;
if(t->cnt > 1)
{
t->siz--;
t->cnt--;
}
else if(t->ch[0]==0)
{
t=t->ch[1];
delete tmp;
tmp=0;
}
else if(t->ch[1]==0)
{
t=t->ch[0];
delete tmp;
tmp=0;
}
else
{
int e=t->ch[0]->key > t->ch[1]->key ? 1 : 0;
rot(t,e);
del(t->ch[e],x);
}
}
else
{
t->siz--;
del(t->ch[d],x);
}
if(t!=0) t->update();//防止删空
}
int rnk(node* &t,int x)
{
int d = t->compare(x),delta;
if(!t->ch[0]) delta=0;
else delta=t->ch[0]->siz;
if(d==-1)
return delta+1;
else if(!d)
return rnk(t->ch[d],x);
else
return rnk(t->ch[1],x)+delta+t->cnt;
}
int kth(node* &t,int k)
{
if(t->ch[0]==0&&k>=1&&k<=t->cnt) return t->val;
if(!t->ch[0]) return kth(t->ch[1],k - t->cnt);
if(t->ch[0])
{
tmp=t->ch[0]->siz+t->cnt;
if(k<=tmp&&k > t->ch[0]->siz)
return t->val;
else if(k <= t->ch[0]->siz)
return kth(t->ch[0],k);
else return kth(t->ch[1],k-tmp);
}
}
void aft(node *t,int x){
if(!t) return;
int d=t->compare(x);
if(d==1||d==-1)
aft(t->ch[1],x);
else if(!d)
{
pst=t->val;
aft(t->ch[0],x);
}
}
void bef(node *t,int x){
if(!t) return;
int d=t->compare(x);
if(d==1)
{
pre=t->val;
bef(t->ch[1],x);
}
else if(d==0||d==-1)
bef(t->ch[0],x);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&opt,&x);pst=0;pre=0;
switch(opt)
{
case 1:insert(root,x);break;
case 2:del(root,x);break;
case 3:printf("%d\n",rnk(root,x));break;
case 4:printf("%d\n",kth(root,x));break;
case 5:bef(root,x);printf("%d\n",pre);break;
case 6:aft(root,x);printf("%d\n",pst);break;
}
}
return 0;
}
嗯,就是这样。