HDU 6136 Death Podracing(优先队列+双向链表)

解决一个数学问题,涉及多个点在一个圆形路径上以不同速度移动并相互碰撞的情况。使用优先队列和链表来高效地预测和处理碰撞事件。

Description

一个周长为L的圆上有n个点,第i个点的位置为di(从起点开始沿顺时针方向的弧长长度),速度为vi(正值表示顺时针运动,负值表示逆时针运动),所有点的位置和速度均不相同,能量为i,在运动过程中,如果两个点相遇,则能量值较小的点会被淘汰,问何时圆上只剩一个点

Input

第一行一整数T表示用例组数,每组用例首先输入两整数nL分别表示点数和圆的周长,之后输入n个整数di表示点的位置,和n个整数vi表示点的速度(T1000,2n105,1L109,0di<L,0|vi|109,sum{n}2106)

Output

输出只剩一个点的时刻,结果输出最简分数

Sample Input

2
2 4
0 2
3 2
10 100
56 89 62 71 7 24 83 1 47 52
9 -16 34 -38 47 49 -32 17 39 -9

Sample Output

2/1
37/7

Solution

由于速度不同,故最后必然只剩下一个点,维护相邻两点相遇用时,每次选出时间最短的两个点必然是最先碰撞的,把能量值小的删掉后这个点前后的点变成一对相邻点,把这对点的相遇时间求出来接着和其他时间比较,用链表维护点的前后关系,用优先队列维护相遇时间,时间复杂度O(nlogn)

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define maxn 100005
struct Point
{
    int w,d,v;
    bool operator<(const Point &b)const
    {
        return d<b.d;
    }
}p[maxn];
struct node
{
    int u,v,x,y,w;
    bool operator<(const node &b)const
    {
        return 1ll*x*b.y>1ll*b.x*y;
    };
};
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}
priority_queue<node>que;
int T,n,L,Pre[maxn],Next[maxn],vis[maxn];
void get(int i,int j,int &x,int &y)
{
    int di=p[i].d,vi=p[i].v;
    int dj=p[j].d,vj=p[j].v;
    if(vi<vj)swap(di,dj),swap(vi,vj);
    y=vi-vj;
    if(di<dj)x=dj-di;
    else x=L+dj-di;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&L);
        for(int i=0;i<n;i++)scanf("%d",&p[i].d);
        for(int i=0;i<n;i++)scanf("%d",&p[i].v);
        for(int i=0;i<n;i++)p[i].w=i;
        sort(p,p+n);
        int x,y,g;
        while(!que.empty())que.pop(); 
        for(int i=0;i<n;i++)
        {
            vis[i]=0,Pre[i]=(i-1+n)%n,Next[i]=(i+1)%n;
            get(i,Next[i],x,y);
            que.push((node){i,Next[i],x,y});
        }
        node a;
        for(int k=1;k<n;k++)
        {
            int i,j;
            while(1)
            {
                a=que.top(),que.pop();
                i=a.u,j=a.v;
                if(!vis[i]&&!vis[j])break;
            }   
            if(k==n-1)
            {
                get(i,j,x,y);
                g=gcd(x,y);
                printf("%d/%d\n",x/g,y/g);
                break;
            }       
            if(p[i].w<p[j].w)
            {
                vis[i]=1;
                get(Pre[i],j,x,y);
                que.push((node){Pre[i],j,x,y});
                Next[Pre[i]]=j,Pre[j]=Pre[i];
            }
            else
            {
                vis[j]=1;
                get(i,Next[j],x,y);
                que.push((node){i,Next[j],x,y});
                Next[i]=Next[j],Pre[Next[j]]=i;
            }

        }
    }   
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值