排名

题目描述

小 W 准备参加 IOSJ,但 IOSJ 作为一个选拔性质的比赛会进行很多轮,在每轮之后每位 选手的得分都会发生变化,小 W 想研究这些选手排名的变化情况。 IOSJ 共有 N 位选手,编号依次为[1,N]。第 i 位选手在第一轮结束后的得分为 a[i]。现在小 W 收集到了第二轮的得分情况,第 i 位选手每秒会增加 b[i]分,你可以认为第二轮的时间为无限长。 定义一次排名的“追赶”如下:(1)在某个时刻 x 秒之前(x 可以为小数),编号为 a 的选手分数小于编号为 b 的选手;(2)在时刻 x 秒的时候,编号为 a,b 的两位选手分数相同。 满足以上两点的事件称为“追赶”。现在小 W 想让你求出按照时间排序后前 M 次“追赶”时的编号 a 和编号 b(时间相同追赶者的编号更小的优先,时间和追赶者编号都相同时被追赶者编号更小的优先)。

输入输出格式

输入格式:

 

第一行一个整数 N,表示选手总数。 接下来 N 行,第 i+1 行两个整数表示 a[i],b[i]。 接下来一行一个整数 M。

 

输出格式:

 

共 M 行,第 i 行两个整数分别表示第 i 次追赶的追赶者和被追赶者。

 

输入输出样例

输入样例#1: 复制

2
1 100
3 1
1

输出样例#1: 复制

1 2

输入样例#2: 复制

4
4 2
2 9
9 2
5 6
3

输出样例#2: 复制

2 1
2 3
2 4

说明

对于 10%的数据,满足 N<=500。 对于 30%的数据,满足 N<=10000。 对于 50%的数据,满足 N<=100000,M<=1000。 对于另外 20%的数据,满足 N<=10000,M<=20000。 对于 100%的数据,满足 N,M<=100000,1<=a[i],b[i]<=1000000000,保证存在至少 M 次 追赶,且所有 a[i]互不相同。保证第 M 次和第 M+1 次追赶的时间不相同。

 

使用链表维护所有人的相对位置,那么一个人超过另一个人的时候只要把链表中两个相邻的
数进行交换。在维护链表的同时把每一组相邻的人的超越时间放到一个堆中,那么下一次的
超越就是堆顶的事件。
#include<bits/stdc++.h>
#define f(i,l,r) for(i=(l);i<=(r);i++)
using namespace std;
const int MAXN=100005,MOD=10000019;
double EPS=1e-9;
struct Node{
    int a,b,id;
    bool operator < (const Node& tmp)const{
        return a<tmp.a;
    }
}e[MAXN];
struct Event{
    int u,v;
    bool operator < (const Event& tmp)const{
    	double tim1=1.0*(e[v].a-e[u].a)/(e[u].b-e[v].b);
    	double tim2=1.0*(e[tmp.v].a-e[tmp.u].a)/(e[tmp.u].b-e[tmp.v].b);
        if(fabs(tim1-tim2)<EPS){
        	if(e[u].id==e[tmp.u].id) return e[v].id<e[tmp.v].id;
        	return e[u].id<e[tmp.u].id;
		}
		return tim1<tim2;
    }
};
set<Event> q,p;
int n,m;
int l[MAXN],r[MAXN];
void Swap(int x,int y)
{
	r[l[x]]=y;
    l[y]=l[x];
    l[x]=y;
	r[x]=r[y];
    l[r[y]]=x;
    r[y]=x;
}
int main()
{
    ios::sync_with_stdio(false);
    int i,j;
    cin>>n;
    f(i,1,n){
        cin>>e[i].a>>e[i].b;
        e[i].id=i;
    }
    cin>>m;
    sort(e+1,e+1+n);
    f(i,1,n){
        l[i]=i-1;
        r[i]=i+1;
    }
    f(i,1,n-1){
        if(e[i].b<=e[i+1].b) continue;
        double tim=1.0*(e[i+1].a-e[i].a)/(e[i].b-e[i+1].b);
        q.insert((Event){i,i+1});
    }
   f(i,1,m){
      	set<Event>::iterator it=q.begin();
      	q.erase(it);
      	Event cur=*it;
      	p.insert(cur);
        if(l[cur.u]){
			if(e[l[cur.u]].b>e[cur.v].b){
       	 	//	double tim=1.0*(e[cur.v].a-e[l[cur.u]].a)/(e[l[cur.u]].b-e[cur.v].b);
        		q.insert((Event){l[cur.u],cur.v});
        	}
        }
       	if(r[cur.v]<=n){
		    if(e[cur.u].b>e[r[cur.v]].b){
        		q.insert((Event){cur.u,r[cur.v]});
  			}
        }
		Swap(cur.u,cur.v);
    }
  	f(i,1,m){
    	set<Event>::iterator it=p.begin();
      	p.erase(it);
      	Event cur=*it;
        cout<<e[cur.u].id<<" "<<e[cur.v].id<<endl;
	}
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值