題目描述
小明是個蛋糕愛好者,連做夢都想着喫蛋糕——然後,他真的作了這樣一個夢:
現在他在一個長爲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;
}