[poj 2274] The Race 堆

题目大意:飞船往同一方向飞,已知每个飞船的起点(不重合)和速度,问题一:每个飞船被超过的次数的总和(模1000000);

问题二:输出前10000次超越,按照时间排序,若时间相同按照超越别飞船的飞船的输入顺序排序。

第一个问题可以看出是求逆序数,并且输入因为有序,所以可以在线处理,并且因为数据十分小,最大100,所以完全可以暴力枚举。

而使用线段树求逆序数也是很简单的问题,可以略过。

第二个问题我是使用最小堆维护时间,距离,每次取出堆头,并更新位置,再将新出现的超车可能性加入堆中。

堆维护是维护相邻的船,所以当发现取出的堆头与当前条件不符时,可以直接continue。

这里有用线段树打第二个问题的可以看看

#include <cstdio>
#include <queue>
#include <cmath>
#define mid ((l+r)/2)
using namespace std;
struct CAR{
	int x,v;
}car[250005];
const double eps=1e-8;
int tree[5005];
int n,ans;
int pre[250005],nxt[250005];
struct heap{
	double t,dis;
	int car1,car2;
	heap(double t,double dis,int car1,int car2):t(t), dis(dis), car1(car1), car2(car2){}
	bool operator < (heap x) const
	{
		if (fabs(t-x.t)<eps) return dis>x.dis;
		return t>x.t;
	}
};
void insert(int l,int r,int v,int k)
{
	if (l==r)
	{
		tree[k]++;
		return;
	}
	if (v<=mid) insert(l,mid,v,k*2);
	else insert(mid+1,r,v,k*2+1);
	tree[k]=tree[k*2]+tree[k*2+1];
}
int ask(int l,int r,int k,int x,int y)
{
	if (x<=l&&y>=r)
	{
		return tree[k];
	}
	int ans=0;
	if (x<=mid) ans+=ask(l,mid,k*2,x,y);  
    if (y>mid) ans+=ask(mid+1,r,k*2+1,x,y);
    return ans;
}
priority_queue<heap> q;
int main()
{
	register int i,j;
	scanf("%d",&n);
	for (i=1;i<=n;i++)
	{
		pre[i]=i-1;nxt[i]=i+1;
		scanf("%d %d",&car[i].x,&car[i].v);
		ans+=ask(1,100,1,car[i].v+1,100);
		insert(1,100,car[i].v,1);
		ans%=1000000;
	}
	printf("%d\n",ans);
	for (i=1;i<n;i++)
	{
		if (car[i].v>car[i+1].v)
		{
			double t=(car[i+1].x-car[i].x)/(double)(car[i].v-car[i+1].v);
			q.push(heap(t,(double)(car[i].x+(double)t*car[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.car1]!=hp.car2||pre[hp.car2]!=hp.car1) continue;
		nxt[hp.car1]=nxt[hp.car2];
		pre[hp.car2]=pre[hp.car1];
		nxt[hp.car2]=hp.car1;
		pre[hp.car1]=hp.car2;
		nxt[pre[hp.car2]]=hp.car2;
		pre[nxt[hp.car1]]=hp.car1;
		if (nxt[hp.car1]<=n&car[hp.car1].v>car[nxt[hp.car1]].v)
		{
			double t=(double)(car[nxt[hp.car1]].x+car[nxt[hp.car1]].v*hp.t-hp.dis)/(car[hp.car1].v-car[nxt[hp.car1]].v);
			q.push(heap(hp.t+t,(double)(hp.dis+(double)car[hp.car1].v*t),hp.car1,nxt[hp.car1]));
		}
		if (pre[hp.car2]&&car[pre[hp.car2]].v>car[hp.car2].v)
		{
			double t=(double)(hp.dis-car[pre[hp.car2]].v*hp.t-car[pre[hp.car2]].x)/(car[pre[hp.car2]].v-car[hp.car2].v);
			q.push(heap(hp.t+t,(double)(hp.dis+(double)car[hp.car2].v*t),pre[hp.car2],hp.car2));
		}
		printf("%d %d\n",hp.car1,hp.car2);i++;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值