CF1239C Queue in the Train
(话说翻译还是我提交的,不过欢迎大家来踩)
比赛第一思路是用线段树,但是过于毒瘤导致没时间写完(虽然最后还是小组第一嘤嘤嘤)
考虑直接模拟
时间段很长,但是时间点很少,每个人的ti带来n个时间点,接水结束带来n个时间点,共2n个时间点。
由于本题中要求的全是最值(最靠左的。。最早的。。等等)
以及“判断有多少人到时间”也可以转化为“多次询问当前时间要求最小的人是否到时间,若到时间了就取出那个人”。反正全都是求最值的问题,既然是只要最值,那就上直接优先队列。
每次log模拟,再跳时间点,一共2n次,所以复杂度是nlogn的
(这里用到了自己封装的一个对顶堆,支持删除的堆,待会再讲)
需要开的结构有:
一个堆,sitting,表示现在还未打算打水的人,按照键值为ti从小到大排序
一个堆,preparing,表示现在想要打水,但是不去排队的人,按照键值为pos(座位编号)从小到大排序
一个可删除堆,inque,表示现在正在排队的人,按照键值为pos从小到大排序
一个普通的队列,queorder,顾名思义,存的也是正在排队的人,不过不排序,也就是“谁先插入谁在前”。单纯模拟现在排队的队列。
由于考虑的是模拟,现在就来想想会遇到什么情况:
- 没有人排队,但是时间太早了以至于大家都坐着不想喝水。这个时候由于
sitting中是按ti排序的,直接查看sitting.top().t并把当前时间(curtime)直接跳到sitting.top().t,接着不停地把sitting中到达curtime的节点(ti<=curtime)转移到preparing中,最后把preparing中座位最靠左的人转移到inque和queorder中。
此部分代码如下:
if(!inque.size()&&sitting.size())
{
curtime=sitting.top().t;
while(sitting.size()&&sitting.top().t<=curtime)
preparing.push(sitting.top()),sitting.pop();
inque.push(preparing.top()),queorder.push(preparing.top()),preparing.pop();
}
-
排在第一位的人正在接水,在他接水的这段时间内,有些人(这些人在
sitting中)想要打水,分两种情况:①在他之前(编号小于他)的人都坐着,这时由于
sitting是按时间排序的,最先想打水的人可以直接起身去排队,所以我们就直接把这个人转移到inque和queorder中,而不用经过preparing②在他之前(编号小于他)的座位有的空着,这时候即使他想打水也不会起身排队,于是把他丢到
preparing中
此部分代码如下:
while(sitting.size()&&sitting.top().t<=curtime)
if(sitting.top().pos<inque.top().pos)
inque.push(sitting.top()),queorder.push(sitting.top()),sitting.pop();
else
preparing.push(sitting.top()),sitting.pop();
(因为inque是将“正在排队的人”按照pos排过序了的,所以inque.top()就是现在正在排队的人中位置(座位)最靠左的人)
- 排在第一位的人打完水,回到座位,这个瞬间会有一些准备起身(
preparing)人要起身打水。根据题目描述,多人打算同时起身时,最靠左的人会起身,其他的会坐下,所以直接把preparing.top()丢进inque和queorder中
此部分代码如下:
inque.delete_(queorder.front()),queorder.pop();
while(sitting.size()&&sitting.top().t<=curtime)
preparing.push(sitting.top()),sitting.pop();
if(preparing.size()&&(!inque.size()||preparing.top().pos<inque.top().pos))
inque.push(preparing.top()),queorder.push(preparing.top()),preparing.pop();
while一下循环做上面三个步骤即可。。。
最后再介绍一下可删除堆(其实在给pos开个数组打标记也可,但是我不想这么做)其实就是另开一个“del”堆
保证∀x∈del,x∈que,这里的que指得是原堆。del中的元素就是要删除的元素,这样在查top的时候判一下,两个堆的对顶是否相等,若相等则两个都pop,一直pop到不等或del为空为止。
证明太水就不证了,下面就是整体代码:
#include<cstdio>
#include<queue>
typedef long long Int;
const int MaxN=100000,inf=0x3f3f3f3f;
inline void read(int &ans)
{
ans=0;
char c=getchar();
while(c<'0'||c>'9')
c=getchar();
while(c>='0'&&c<='9')
ans=ans*10+c-48,c=getchar();
return;
}
int n,P;
struct Node
{
int pos,t;
friend inline bool operator == (const Node &a,const Node &b)
{
return a.pos==b.pos&&a.t==b.t;
}
};
struct cmp_time
{
inline bool operator () (const Node &a,const Node &b) const
{
return a.t==b.t?a.pos>b.pos:a.t>b.t;
}
};
struct cmp_pos
{
inline bool operator () (const Node &a,const Node &b) const
{
return a.pos>b.pos;
}
};
template<typename Element,typename cmp>struct Exque
{
private:
std::priority_queue<Element,std::vector<Element>,cmp>que,del;
public:
inline int size()
{
return que.size()-del.size();
}
inline void pop()
{
if(del.size()&&que.top()==del.top())
del.pop();
return que.pop();
}
inline void push(const Element &x)
{
return que.push(x);
}
inline void delete_(const Element &x)
{
return que.top()==x?que.pop():del.push(x);
}
inline Element top()
{
while(del.size()&&que.top()==del.top())
que.pop(),del.pop();
return que.top();
}
};
std::priority_queue<Node,std::vector<Node>,cmp_time>sitting;
std::priority_queue<Node,std::vector<Node>,cmp_pos>preparing;
Exque<Node,cmp_pos>inque;
std::queue<Node>queorder;
Int ans[MaxN+1];
int cnt=0;
int main()
{
// freopen("test.in","r",stdin);
int i,t;
Int curtime=inf;
read(n),read(P);
for(i=1;i<=n;++i)
{
read(t),sitting.push((Node){i,t});
if(t<curtime)
curtime=t;
}
while(sitting.size()&&sitting.top().t<=curtime)
preparing.push(sitting.top()),sitting.pop();
if(preparing.size()&&(!inque.size()||preparing.top().pos<inque.top().pos))
inque.push(preparing.top()),queorder.push(preparing.top()),preparing.pop();
while(cnt<n)
{
++cnt,ans[queorder.front().pos]=(curtime+=P);
while(sitting.size()&&sitting.top().t<=curtime)
if(sitting.top().pos<inque.top().pos)
inque.push(sitting.top()),queorder.push(sitting.top()),sitting.pop();
else
preparing.push(sitting.top()),sitting.pop();
inque.delete_(queorder.front()),queorder.pop();
while(sitting.size()&&sitting.top().t<=curtime)
preparing.push(sitting.top()),sitting.pop();
if(preparing.size()&&(!inque.size()||preparing.top().pos<inque.top().pos))
inque.push(preparing.top()),queorder.push(preparing.top()),preparing.pop();
if(!inque.size()&&sitting.size())
{
curtime=sitting.top().t;
while(sitting.size()&&sitting.top().t<=curtime)
preparing.push(sitting.top()),sitting.pop();
inque.push(preparing.top()),queorder.push(preparing.top()),preparing.pop();
}
}
for(i=1;i<=n;++i)
printf("%I64d ",ans[i]);
putchar('\n');
return 0;
}

浙公网安备 33010602011771号