1208: [HNOI2004]宠物收养所
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2796 Solved: 995
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
0 2
0 4
1 3
1 2
1 5
Sample Output
(abs(3-2) + abs(2-4)=3,最后一个领养者没有宠物可以领养)
HINT
Source
评测链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1208
解法:SBT。需要用到sbt中的插入、删除、查找。
对于sbt不熟的,可以点击这个链接:http://pan.baidu.com/share/link?shareid=411971&uk=255096381&third=15,里面是我初学sbt时所用的资料。
在sbt树中,要么全是宠物,要么全是人,可以用一个flag标记记录sbt树中是人还是宠物。
每读入一次a、b:
①若a==flag,就向sbt树中插入节点,至于maintain与旋转操作,就只有靠自己去悟了;
②若a!=flag,就在树中查找b的前驱与后继,所谓前驱,即sbt树中,<=b的最大值,后继则与之相反,最优值必定为前驱与后继中的一个,暂且把最优值记为点p[X](p记录每个点的特点值)。知道X后,不满意程度也就知道了,然后累加起来即可。至于删除点X的操作,则是找到p[X]在sbt树中的前驱结点k,将X号点的值赋值为k号节点的值,然后直接删除k号点即可(将k号点的父亲指向k的标记清零即可)。
在下面的代码中的delete(),就是用p【X】的前驱节点的值赋给X节点,并把k号点的父亲指向k的标记清零,来实现删除的,不太懂的,可以自己去模拟一下。若不理解,也可以按照上面说的,单独去找到X的前驱结点K,再将k节点的值赋给X节点,然后再对k进行删除(将k号点的父亲指向k的标记清零)。
代码:
#include<cstdio>
#include<cctype>
#include<algorithm>
#define maxn (10000+10)
#define mod 1000000
using namespace std;
int n,root,flag,ans,num,pre,succ;
int s[maxn],l[maxn],r[maxn],p[maxn];
void init()
{
freopen("pet.in","r",stdin);
freopen("pet.out","w",stdout);
}
inline int getin()
{
int ans=0;char tmp;
while(!isdigit(tmp=getchar()));
do ans=(ans<<3)+(ans<<1)+tmp-'0';
while(isdigit(tmp=getchar()));
return ans;
}
inline void right_rotate(int &t)
{
int k=l[t];
l[t]=r[k];
r[k]=t;
s[k]=s[t];
s[t]=s[l[t]]+s[r[t]]+1;
t=k;
}
inline void left_rotate(int &t)
{
int k=r[t];
r[t]=l[k];
l[k]=t;
s[k]=s[t];
s[t]=s[l[t]]+s[r[t]]+1;
t=k;
}
void maintain(int &t,bool flag)
{
if(flag)
if(s[l[l[t]]]>s[r[t]])
right_rotate(t);
else
if(s[r[l[t]]]>s[r[t]])
left_rotate(l[t]),right_rotate(t);
else
return;
else
if(s[r[r[t]]]>s[l[t]])
left_rotate(t);
else
if(s[l[r[t]]]>s[l[t]])
right_rotate(r[t]),left_rotate(t);
else
return;
maintain(l[t],1);
maintain(r[t],0);
maintain(t,1);
maintain(t,0);
}
void insert(int &t,int w)
{
if(t==0)
{
t=++num;
s[t]=1,l[t]=r[t]=0,p[t]=w;
return;
}
s[t]++;
if(w<p[t])insert(l[t],w);
else insert(r[t],w);
maintain(t,w<p[t]);
}
void getpre(int t,int b)
{
if(s[t]==0)return;
if(b>=p[t])pre=t,getpre(r[t],b);
else getpre(l[t],b);
}
void getsucc(int t,int b)
{
if(s[t]==0)return;
if(b<=p[t])succ=t,getsucc(l[t],b);
else getsucc(r[t],b);
}
int del (int &t,int w)
{
s[t]--;
if((p[t]==w) || (w<p[t] && l[t]==0) || (w>p[t] && r[t]==0))
{
int k=p[t];
if(l[t]==0 || r[t]==0)t=l[t]+r[t];
else p[t]=del(l[t],p[t]);
return k;
}
else
if(w<p[t])return del(l[t],w);
else return del(r[t],w);
}
void work()
{
n=getin(); int i,a,b;
root=s[1]=num=1,l[1]=r[1]=0;
flag=getin(),p[1]=getin();
for(i=2;i<=n;i++)
{
a=getin(),b=getin();
if(num==0)flag=a;
if(a==flag)insert(root,b);
else
{
num--;
pre=root,getpre(root,b);
succ=root,getsucc(root,b);
if(abs(b-p[pre])<=abs(b-p[succ]))
ans+=abs(b-p[pre]),ans%=mod,del(root,p[pre]);
else
ans+=abs(b-p[succ]),ans%=mod,del(root,p[succ]);
}
}
printf("%d\n",ans%mod);
}
int main()
{
init();
work();
return 0;
}