题目描述
小明是个蛋糕爱好者,连做梦都想着吃蛋糕——然后,他真的作了这样一个梦:
现在他在一个长为L的管道里,坐标从0~L,开始时,他在0这个位置。
一些事件依次发生,比如说,小明想吃蛋糕,或者是蛋糕出现了。
如果小明想吃蛋糕,那么他会挑选最近的那个蛋糕吃掉。如果左右两个蛋糕的距离是一样的,那么他就选择跟吃上一个蛋糕同样移动方向上的。否则,他就选那个距离较近的蛋糕。要是一个蛋糕都没出现,那么他就呆在原地不动。
蛋糕会随机出现在管道的任何位置。
请你统计一下,小明一共走了多少距离。
输入
输入第一行是两个整数L,N。L是管道的长度,N是事件的数量。(1<=L,N<=100000)
接下来N行,首先是一个整数,表示事件的种类:如果是1,表示小明要吃蛋糕,后面什么也没有;如果是0,表示有个蛋糕出现了,后面跟一个整数,表示蛋糕出现的位置。(0<=x<=L)
输出
输出一个整数,表示小明一共走了多少距离。
样例输入
10 8
0 1
0 5
1
0 2
0 0
1
1
1
样例输出
9
提示
【样例输入2】
10 7
0 1
0 5
1
0 2
0 0
1
1
【样例输出2】
4
【数据描述】
对于50%的数据,L,N<=5000
对于100%的数据,L,N<=100000
想法
- 用两个堆来维护左边与右边
算法
- 见代码
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
using namespace std;
priority_queue<int> l;
priority_queue<int,vector<int>,greater<int> > r;
int L,N,now,opt,pos,ans,cnt;
bool dir=1;
inline void work(int x)
{
int temp;
if(x)
{
temp=r.top();r.pop();
ans+=temp-now;
now=temp;dir=1;
}
else
{
temp=l.top();l.pop();
ans+=now-temp;
now=temp;dir=0;
}
}
int main()
{
scanf("%d%d",&L,&N);
for (int i=1;i<=N;i++)
{
scanf("%d",&opt);
if(!opt)
{
scanf("%d",&pos);
if(pos==now)cnt++;
else pos>now?r.push(pos):l.push(pos);
}
else
{
if(cnt>0){cnt--;continue;}
else if(l.empty()||r.empty())
{
if(l.empty()&&r.empty())continue;
else if(l.empty())work(1);
else if(r.empty())work(0);
}
else
{
int ll=l.top(),rr=r.top();
if(now-ll==rr-now){work(dir);continue;}
else
now-ll>rr-now?work(1):work(0);
}
}
}
cout<<ans<<endl;
return 0;
}