题目大意:给出一些往同一个方向飞的飞船的初始位置和速度,第一问要求发生超车(超船?)的总次数(%1000000);
第二问要求按超车时间依次给出前10000次超车的飞船的编号与被超车的飞船的编号,如果超车时间相同貌似是根据超过别的飞船的飞船的位置(?)
第一问比较简单,因为读入按照位置依次给出,因为V的范围小,直接用暴力过:先读入的速度如果比后读入的快就能超过,详见代码
对于第二问,首先要明确的是每次发生超车一定是相邻的两艘飞船因为我做之前就知道这道题可以用堆,并且偷偷看了很多题解,思路就比较清晰了
考虑有这么几艘飞船,按位置以此编号为 a,b,c,d
在某个时刻b超过了c顺序就变成了 a,c,b,d
我们就根据相邻两艘飞船的超车时间建立一个小根堆:如上一个例子,若b和c是将发生超车的一组中最快发生超车的,那么除了这四个之间的相对位置会改变外不影响别的飞船于是,我们只要将会发生超车的飞船整对放入小根堆中,每次取出堆顶的一对飞船,进行输出并放入新的元素
---------------
AC代码:
#include<cstdio>
#include<queue>
#define LL long long
using namespace std;
const int Maxn=250001;
struct Node{
int x,y;
double time,w;
bool operator < (const Node &a) const
{
return a.time<time || a.time==time && a.w<w;
}
};
int len,n,x[Maxn],v[Maxn],sum[101],next[Maxn],pre[Maxn];
LL ans=0;
priority_queue <Node> heap;
void add(int i,int j)
{
if(v[i]<=v[j]) return;
double time,w;
time=1.0*(x[j]-x[i])/(v[i]-v[j]);
w=1.0*time*v[i]+x[i];
heap.push((Node){i,j,time,w});
return;
}
void init() //避免一些特殊情况,比如 n=1
{
next[0]=1,pre[n+1]=n;
x[0]=0,v[0]=-1e8;
x[n+1]=1e8,v[n+1]=1e8;
add(0,1);
}
void update(int tx,int ty,int tp,int tn)
{
pre[tx]=ty,next[tx]=tn;
pre[ty]=tp,next[ty]=tx;
pre[tn]=tx,next[tp]=ty;
add(tx,tn);
add(tp,ty);
add(ty,tx);
return;
}
int main()
{
scanf("%d",&n);
init();
int i,j;
for(i=1;i<=n;++i)
{
scanf("%d %d",&x[i],&v[i]);
for(j=v[i]+1;j<=100;++j)
ans=(ans+sum[j])%1000000;
++sum[v[i]];
}
printf("%d\n",ans);
for(i=1;i<=n;++i)
{
next[i]=i+1,pre[i]=i-1;
add(i,next[i]);
}
for(i=1;i<=10000;++i)
{
if(heap.empty())
break;
Node tmp=heap.top();
heap.pop();
if(next[tmp.x]!=tmp.y||pre[tmp.y]!=tmp.x) //判断堆中的元素是否还有效
{
--i;
continue;
}
printf("%d %d\n",tmp.x,next[tmp.x]);
update(tmp.x,next[tmp.x],pre[tmp.x],next[tmp.y]); //超车发生后自然会发生位置的变化,于是与本次超车有关的那些飞船的相对位置会发生改变,需要添加新的元素
}
return 0;
}
---------------
写给自己:第一次写博客本来想水的,因为怕以后质量反而更差,但是转念一想这样还有什么意义呢于是就找了一道个人认为比较厉害的题目,写的可能不好 代码可能很垃圾 效率可能很低。但是我很开心迈出了第一步