题解:P11178 [ROIR 2018 Day1] 电梯
题意
一座有
电梯每秒可以上升或下降一层。若它收到信号它会优先响应最早的信号,同时接受的信号中优先响应编号最小员工的信号。
每当电梯接受信号,它从一层出发来到发出信号的那一层,然后回到一层,它在下降的过程中如果有人已经在等待也会一同承载电梯来到一层。
问按照已有信息,每个员工抵达一层的时间。
思路
先根据题意,按照电梯接受信号的优先级对员工信息排序,然后模拟电梯移动过程。
令当前时间为
模拟时,每次从队头取出一个信号
此次接到的员工有两种,一种是发出信号的员工,还有电梯接完发出信号员工后往下走时遇到的在电梯口等待的员工。这些员工抵达一层的时间是一样为
问题的重点在于确定会被接走的员工编号是哪些。对于第一种员工,编号已经得到了,不作讨论。对于第二种员工,又分为两种了,一种是在电梯出发前就已经在
对于电梯出发前就已经在等待的员工,他们肯定在
对于电梯出发后才赶到电梯口的,他们赶到电梯口的时间一定是在区间
同一个信号会被优先队列和队列同时接收,但是出答案时只会从一个地方弹出,所以在处理这些信号时要特判是否已经被弹出,免得重复计算导致答案错误。
update:2025/8/25 更新了放错的代码
code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,cnt;
long long nt,ans[N];
struct pl{
int id,t,a;
bool operator<(pl b)const{
return a>b.a;
}
}p[N];
inline bool cmp(pl a,pl b){
return a.t!=b.t?a.t<b.t:a.id<b.id;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,t,a;i<=n;i++){
scanf("%d%d",&t,&a);
p[i]={i,t,a};
}
sort(p+1,p+n+1,cmp);
queue<pl>q;
priority_queue<pl>qq;
while(cnt<n||!q.empty()){
if(q.empty()){
q.push(p[++cnt]);
qq.push(p[cnt]);
}
int h=q.front().a;
int u=h-1;
nt=max(nt,(long long)q.front().t);
ans[q.front().id]=nt+u*2;
q.pop();
while(!qq.empty()){
if(ans[qq.top().id])qq.pop();
else if(qq.top().a<=h){
ans[qq.top().id]=nt+u*2;
qq.pop();
}
else break;
}
while(cnt<n&&p[cnt+1].t<=nt+u*2){
++cnt;
if(p[cnt].a<=h&&p[cnt].t<=nt+u+h-p[cnt].a)
ans[p[cnt].id]=nt+u*2;
else{
q.push(p[cnt]);
qq.push(p[cnt]);
}
}
while(!q.empty()&&ans[q.front().id])q.pop();
nt+=u*2;
}
for(int i=1;i<=n;i++)printf("%lld\n",ans[i]);
return 0;
}