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

来源:互联网 发布:java定义数组并赋值 编辑:程序博客网 时间:2024/06/01 09:30

The Race
Time Limit: 15000MS Memory Limit: 65536KTotal Submissions: 3685 Accepted: 756Case 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

40 22 13 86 3

Sample Output

23 41 2





题意:

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

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

问超车的次数

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







对于超车次数:

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

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


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

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


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

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


题目中定义速度大小只在  ( 0 , 100 )  这个范围中,但是好像题目内部测试数据好像有 速度为 0  的情况
40 51 43 14 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|1int 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;}


0 0
原创粉丝点击