《算法艺术与信息学竞赛》之 堆 The Race

During the Annual Interstellar Competition for Tuned Spaceships, N spaceships will be competing. Each spaceship i is tuned in such a way that it can accelerate in zero time to its maximum speed Vi and remain cruising at that speed. Due to past achievements, each spaceship starts at a starting position Xi, specifying how many kilometers the spaceship is away from the starting line.
The race course is infinitely long. Because of the high speeds of the spaceships, the race course goes straight all the time. On that straight course, spaceships can pass one another very easily, without interfering with each other.
Many people in the audience have not realized yet that the outcome of the race can be determined in advance. It is your task to show this to them, by telling them how many times spaceships will pass one another, and by predicting the first 10 000 times that spaceships pass in chronological order.
You may assume that each spaceship starts at a different position. Furthermore, there will never be more than two spaceships at the same position of the course at any time.

Input
The first line of the input specifies the number of spaceshipsN (0 < N <= 250 000) that are competing. Each of the next N lines describe the properties of one spaceship. The i+1th line describes the ith ship with two integers Xi and Vi, representing the starting position and the velocity of the ith spaceship (0 <= Xi <= 1 000 000, 0 < Vi < 100). The spaceships are ordered according to the starting position, i.e. X1 < X2 < … < XN. The starting position is the number of kilometers past the starting line where the spaceship starts, and the velocity is given in kilometers per second.
Output
The first line of the output should contain the number of times that spaceships pass one another during the race modulo 1 000 000. By publishing the number of passes only modulo 1 000 000, you can at the same time prove your knowledge of it and don’t spoil the party for the less intelligent people in the audience.
Each of the subsequent lines should represent one passing, in chronological order. If there would be more than 10 000 passings, only output the first 10 000 passings. If there are less than 10 000 passings, output all passings. Each line should consist of two integers i and j, specifying that spaceship i passes spaceship j. If multiple passings occur at the same time, they have to be sorted by their position on the course. This means that passings taking place closer to the starting line must be listed first. The time of a passing is the time when the two spaceships are at the same position.
Sample Input
4
0 2
2 1
3 8
6 3
Sample Output
2
3 4
1 2

本题的模拟过程较为麻烦,分为两问,第一问就是一个求逆序对的问题,这里不多说,博主蒟蒻只会用归并求,第二问是一个事件模拟,首先整理一些信息:每辆车前面是哪一辆车,多久后可以超过。然后用堆来模拟。(这里注意一下,时间一定不能用相对时间,而要用绝对时间,否则很难用堆实现)接下来注意到一个问题,我们每次超车过后,就会需要更改每辆车的前后位置,发现只记录每辆车前面是那一辆会很难处理,所以我们多开一个数组来处理每一辆车前面是那辆车,就能在很快的时间内完成这一过程。
接下来上代码:

#include<bits/stdc++.h>
using namespace std;
struct node{
    int x,v;
}node[250005];
const double eps=1e-8;
int tree[5005];
int n,ans,a[250005],b[250005];
int pre[250005],nxt[250005];
struct heap{
    double t,dis;
    int node1,node2;
    heap(double t,double dis,int node1,int node2):t(t), dis(dis), node1(node1), node2(node2){}
    bool operator<(heap x) const{//建堆需要重载小于号 
        if (fabs(t-x.t)<eps) return dis>x.dis;
        return t>x.t;
    }
};
void merge(int l,int mid,int r){
    int i=l,j=mid+1,k=l;
    while(i<=mid&&j<=r){
        if(a[i]<=a[j])b[k++]=a[i++];
        else{
            b[k++]=a[j++];
            ans+=mid-i+1;
            ans%=1000000;
        }
    }
    while(j<=r)b[k++]=a[j++];
    while(i<=mid)b[k++]=a[i++];
    for(k=l;k<=r;k++)a[k]=b[k];
}
void mergesort(int l,int r){
    if(l>=r)return;
    int mid=(l+r)>>1;
    mergesort(l,mid);
    mergesort(mid+1,r);
    merge(l,mid,r);
}//归并排序求逆序对 
priority_queue<heap> q;
int main(){
    int i,j;
    scanf("%d",&n);
    for (i=1;i<=n;i++){
        pre[i]=i-1;nxt[i]=i+1;
        scanf("%d %d",&node[i].x,&node[i].v);
        a[i]=node[i].v;
    }
    mergesort(1,n);
    printf("%d\n",ans);
    //处理超车 
    for(i=1;i<n;i++){
        if (node[i].v>node[i+1].v){
            double t=(node[i+1].x-node[i].x)/(double)(node[i].v-node[i+1].v);
            q.push(heap(t,(double)(node[i].x+(double)t*node[i].v),i,i+1));
            heap hp=q.top();//计算时间 
        }
    }
    for(i=1;i<=10000&&!q.empty();){
        heap hp=q.top();q.pop();
        if (nxt[hp.node1]!=hp.node2||pre[hp.node2]!=hp.node1) continue;
        nxt[hp.node1]=nxt[hp.node2];
        pre[hp.node2]=pre[hp.node1];
        nxt[hp.node2]=hp.node1;
        pre[hp.node1]=hp.node2;
        nxt[pre[hp.node2]]=hp.node2;
        pre[nxt[hp.node1]]=hp.node1;//更新nxt与pre数组,即车辆的前后位置关系 
        if (nxt[hp.node1]<=n&node[hp.node1].v>node[nxt[hp.node1]].v){
            double t=(double)(node[nxt[hp.node1]].x+node[nxt[hp.node1]].v*hp.t-hp.dis)/(node[hp.node1].v-node[nxt[hp.node1]].v);
            q.push(heap(hp.t+t,(double)(hp.dis+(double)node[hp.node1].v*t),hp.node1,nxt[hp.node1]));
        }
        if (pre[hp.node2]&&node[pre[hp.node2]].v>node[hp.node2].v){
            double t=(double)(hp.dis-node[pre[hp.node2]].v*hp.t-node[pre[hp.node2]].x)/(node[pre[hp.node2]].v-node[hp.node2].v);
            q.push(heap(hp.t+t,(double)(hp.dis+(double)node[hp.node2].v*t),pre[hp.node2],hp.node2));
        }
        printf("%d %d\n",hp.node1,hp.node2);i++;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值