poj 2274 线段树+堆(优先队列)

博客详细介绍了如何运用线段树和优先队列解决POJ 2274题目,即计算在给定的飞船速度和位置情况下,超车的次数及具体超车信息。线段树用于逐个更新和查询数字的相对大小,而优先队列用于处理超车顺序。文章通过代码解释了线段树的构建与查询过程,并定义了优先队列中的节点结构,以便维护最小堆并调整飞船位置。

The Race
Time Limit: 15000MS Memory Limit: 65536K
Total Submissions: 3685 Accepted: 756
Case Time Limit: 3000MS

Description

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





题意:

给出 n 个飞船,都是走直线的

给出每一个飞船相对于出发线的位置,和各自的速度

问超车的次数

并且输出超车的的号码(某某超某某)







对于超车次数:

使用线段树:这里线段树是逐个更新的(在线处理)

                        每一次输入一个数字查询之前的数字中有多少比它大的个数


                  本题中对于线段树可以建树也可以不用建树,下面我已经把建树的代码注释掉了

       然后这里对于查询和更新的函数的顺序有讲究


必须  x 先 进入线段树,因为速度可以为 0 (下面讨论速度为 0  的情况)

然后查询 【x+1 ,100】这个区间的数(就是查询速度比它大可以超过它的车的数量)


题目中定义速度大小只在  ( 0 , 100 )  这个范围中,但是好像题目内部测试数据好像有 速度为 0  的情况
4
0 5
1 4
3 1
4 0
这是discuss中的测试数据,比较了一下自己的逆序数计算法和别人AC 的代码,线段树的不同,然后改对了就过了

可能是自己线段树没有学好,才刚入门







优先队列(堆):

对于超车的谁超谁的输入问题

我们定义结构体,作为这个优先队列中的每一个节点,具体见代码

维护一个最小堆(算法导论上面有方法)

调整四条飞船的位置就好了





#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

#define MAXN 250010
#define INF 0x3f3f3f3f
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1

int n;
int pos[MAXN],v[MAXN];
int sum[MAXN<<2];

int next[MAXN],pre[MAXN];
int top;

//******************线段树************************//

//-----------在[l,r]区间建树,从p开始--------------//
/*
void build(int l,int r,int p)
{
    sum[p]=0;
    if(l==r)
        return ;
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
}
*/


//----------在[l,r]中查询[L,R],从p开始--------------//
int query(int L,int R,int l,int r,int p)
{
    if (l>=L&&r<=R)
        return sum[p];

    int mid=(l+r)>>1;
    int ans=0;
    if (mid>=L)
        ans+=query(L,R,lson);
    if (mid<R)
        ans+=query(L,R,rson);
    return ans%1000000;
}
//-----------注意上叙不能用else---------------------//



//--------从[l,r]更新数字num,起点p-----------------//
void update(int num,int l,int r,int p)
{
    if(l==r){
       sum[p]++;//叶子
       return;
    }

    int mid=(l+r)>>1;
    if(num<=mid)
        update(num,lson);
    else
        update(num,rson);

    sum[p]=(sum[p<<1]+sum[p<<1|1])%1000000;//非叶子节点
}




//************************************************//
//************************************************//
//************************************************//
//****************优 先 队 列*********************//
//************************************************//
//************************************************//
struct node
{
    int x,y;//x 是坐标 ,y 记录 x 的后节点
    double k1,k2;//k1记录时间,k2表示行进的距离
//-------------构造函数初始化----------------------//
    node()
    {
        x=0;y=0;
        k1=0;k2=0;
    }
    node(int x1,int y1,double t1,double t2)
    {
        x=x1;y=y1;
        k1=t1;k2=t2;
    }
}heap[MAXN*10];


void Swap(int i,int j)
{
    node t;
    t=heap[i];
    heap[i]=heap[j];
    heap[j]=t;
}
//--------------函数重载--------------------------//
bool operator<(node a,node b)
{
    return a.k1<b.k1||(a.k1==b.k1&&a.k2<b.k2);
}







void heap_increase(int i)//算法导论91页
{
    while(i>1)//保证不超出这棵树的范围
    {
        int j=i>>1;//就是堆中 i 的父亲节点

        //继续维护最小堆
        if(heap[i]<heap[j])
            Swap(i,j);
        else
            break;
        i=j;
    }
}

void heap_decrease(int i)//向堆的下面走
{
    while((i<<1)<=top)//保证不超出这棵树的范围
    {
        int j=i<<1;//i 就是堆中 j 的父亲节点
        if(j+1<=top&&heap[j+1]<heap[j])
            j++;//找最小的儿子维护最小堆


        //继续维护最小堆
        if(heap[j]<heap[i])
            Swap(i,j);
        else
            break;
        i=j;
    }
}

void pri_queue()//优先队列(最小堆)
{

    Swap(1,top);
    top--;
    heap_decrease(1);
}






void add(int i,int j)
{
    double dis,time;
    if(v[i]>v[j])//后者速度大在后面追
        time=double(pos[j]-pos[i])/(v[i]-v[j]);
    else
        time=INF;


    dis=pos[i]+v[i]*time;
    node temp=node(i,j,time,dis);

    heap[++top]=temp;
    heap_increase(top);
}



void deal_heap()
{
    next[0]=1;pre[n+1]=n;
    pos[n+1]=INF;v[n+1]=INF;
    pos[0]=0;v[0]=-INF;
    add(0,1);
    for(int i=1;i<=n;i++){
        next[i]=i+1;
        pre[i]=i-1;
        add(i,next[i]);
    }
//-------------初始化------------------------------//
    for(int i=1;i<=10000;i++){
        if(heap[1].k1>=INF)
            break;

        //判断y的前节点是不是 x
        //x的后节点是不是 y
        if(pre[heap[1].y]!=heap[1].x || next[heap[1].x]!=heap[1].y){
                        --i;
                        pri_queue();
                        continue;
        }

        printf("%d %d\n",heap[1].x,next[heap[1].x]);
        int tempx=heap[1].x,tempy=next[heap[1].x];
        int tempx_pre=pre[tempx],tempy_next=next[tempy];
        pri_queue();



//----------------调整四条飞船的位置--------------------//
        next[tempx_pre]=tempy;     pre[tempy]=tempx_pre;
        next[tempy]=tempx;         pre[tempx]=tempy;
        next[tempx]=tempy_next;    pre[tempy_next]=tempx;


        add(tempx,tempy_next);
        add(tempx_pre,tempy);
        add(tempy,tempx);
    }
}


void init()
{
    //freopen("in.txt","r",stdin);
    scanf("%d",&n);

    int ans=0;
    //build(1,100,1);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&pos[i],&v[i]);
        update(v[i],1,100,1);
        ans+=query(v[i]+1,100,1,100,1);
        ans%=1000000;//注意,这里模百万,但输出一万以内次

    }
    printf("%d\n",ans);
//-----------------------------------------------//
    deal_heap();
}

int main()
{
    init();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值