1. 程式人生 > >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;
}