poj 2274 The Race(逆序数+线段树)

The Race

Time Limit: 15000MS   Memory Limit: 65536K
Total Submissions: 3237   Accepted: 664
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

题意:飞船往同一方向飞,已知每个飞船的起点(不重合)和速度,问题一:每个飞船被超过的次数的总和(模1000000);问题二:输出前10000次超越,按照时间排序,若时间相同按照超越别飞船的飞船的输入顺序排序。

解题思路:
问题一:按照起点排序(输入已经给我们排好),若前一个速度比当前的速度大,则前面那个飞船一定能超越当前飞船,否则不可能。因此,只要算一下逆序数和就可以了。

问题二:第一个超越的一定是相邻两个飞船。
反证:设当前位置为A-B-C,若第一次超越为A->C,则必定A->B或B->C,与A->C为第一次超越矛盾。
因此:

这样,我就能保证每次输入的就是当前最早超越的飞船!
顶层设计完了之后就是实现问题了,逆序数我用的是线段树。寻找超越飞船我也用了线段树,把每段线段当作一个点,然后每次查询最小,单点更新。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

const int maxn1 = 250010;
const int maxn2 = 110;
const int mod = 1000000;
struct tree1{
    int l , r , sum;
}a1[4*maxn2];
struct plane{
    int x , v;
}P[maxn1];
struct tree2{
    int l , r , Max;
}a2[4*maxn1];
struct Node{
    int l , r;
}node[maxn1];
int N;

void build1(int l , int r , int k){
    a1[k].l = l;
    a1[k].r = r;
    a1[k].sum = 0;
    if(l != r){
        int mid = (l+r)/2;
        build1(l , mid , 2*k);
        build1(mid+1 , r , 2*k+1);
    }
}

void add1(int l , int r , int k){
    if(l <= a1[k].l && a1[k].r <= r) a1[k].sum++;
    else{
        int mid = (a1[k].l+a1[k].r)/2;
        if(mid >= r) add1(l , r , 2*k);
        else add1(l , r , 2*k+1);
        a1[k].sum = (a1[2*k].sum+a1[2*k+1].sum)%mod;
    }
}

int query1(int l , int r , int k){
    if(l <= a1[k].l && a1[k].r <= r) return a1[k].sum;
    else{
        int mid = (a1[k].l+a1[k].r)/2;
        if(mid >= r) return query1(l , r , 2*k)%mod;
        else if(l > mid) return query1(l , r , 2*k+1)%mod;
        else return (query1(l , mid , 2*k)+query1(mid+1 , r , 2*k+1))%mod;
    }
}

void pushup(int k){
    if(a2[2*k].Max == -1 && a2[2*k+1].Max == -1) a2[k].Max = -1;
    else if(a2[2*k].Max == -1) a2[k].Max = a2[2*k+1].Max;
    else if(a2[2*k+1].Max == -1) a2[k].Max = a2[2*k].Max;
    else{
        int lson = a2[2*k].Max , rson = a2[2*k+1].Max;
        int lnode = (P[node[lson].r].v-P[node[lson].l].v)*(P[node[rson].r].x-P[node[rson].l].x);
        int rnode = (P[node[rson].r].v-P[node[rson].l].v)*(P[node[lson].r].x-P[node[lson].l].x);
        if(lnode <= rnode) a2[k].Max = a2[2*k].Max;
        else a2[k].Max = a2[2*k+1].Max;
    }
}

void build2(int l , int r , int k){
    a2[k].l = l;
    a2[k].r = r;
    a2[k].Max = -1;
    if(l == r){
        if(P[node[l].l].v <= P[node[l].r].v) a2[k].Max = -1;
        else a2[k].Max = l;
    }else{
        int mid = (l+r)/2;
        build2(l , mid , 2*k);
        build2(mid+1 , r , 2*k+1);
        pushup(k);
    }
}

void update(int l , int r , int k){
    if(l <= a2[k].l && a2[k].r <= r){
        if(P[node[l].l].v <= P[node[l].r].v) a2[k].Max = -1;
        else a2[k].Max = l;
    }else{
        int mid = (a2[k].l+a2[k].r)/2;
        if(r <= mid) update(l , r , 2*k);
        else update(l , r , 2*k+1);
        pushup(k);
    }
}

void computing(){
    for(int i = 1; i < N; i++){
        node[i].l = i;
        node[i].r = i+1;
    }
    build2(1 , N-1 , 1);
    int cnt = 0;
    while(cnt < 10000){
        if(a2[1].Max == -1) break;
        int m = a2[1].Max;
        printf("%d %d\n" , node[m].l , node[m].r);
        swap(node[m].l , node[m].r);
        update(m , m , 1);
        if(m-1 >= 1){
            node[m-1].r = node[m].l;
            update(m-1 , m-1 , 1);
        }
        if(m+1 < N){
            node[m+1].l = node[m].r;
            update(m+1 , m+1 , 1);
        }
        cnt++;
    }
}

void readcase(){
    build1(1 , 100 , 1);
    int ans = 0;
    for(int i = 1; i <= N; i++){
        scanf("%d%d" , &P[i].x , &P[i].v);
        ans = (ans+query1(P[i].v+1 , 100 , 1))%mod;
        add1(P[i].v , P[i].v , 1);
    }
    printf("%d\n" , ans);
    if(ans != 0) computing();
}

int main(){
    while(~scanf("%d" , &N)){
        readcase();
    }
    return 0;
}

poj 2274 The Race(逆序数+线段树),布布扣,bubuko.com

时间: 2024-10-27 00:27:35

poj 2274 The Race(逆序数+线段树)的相关文章

HDU 1394 &lt;Minimum Inversion Number&gt; &lt;逆序数&gt;&lt;线段树&gt;

Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seq

poj 2299 Ultra-QuickSort 求逆序数,树状数组解法,详细解析

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 44554   Accepted: 16195 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

51Nod 1019 逆序数(线段树)

题目链接:逆序数 模板题. 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 6 #define lson i << 1, L, mid 7 #define rson i << 1 | 1, mid + 1, R 8 9 const int N = 100010; 10 11 long long ans

POJ 3162 Walking Race 树形DP+线段树

给出一棵树,编号为1~n,给出数m 漂亮mm连续n天锻炼身体,每天会以节点i为起点,走到离i最远距离的节点 走了n天之后,mm想到知道自己这n天的锻炼效果 于是mm把这n天每一天走的距离记录在一起,成为一段长度为n的数列 现在mm想要从这数列中选出一个连续的区间,要求这个区间的max-min<=m 输出最长的区间 做了一个下午 思路: 分成2个部分: 1.求出数列,即对于一棵树,求出每一个节点能到达的最远距离 2.对于这段数列,选出一个区间,使得区间的max-min<=m,并且使得区间长度尽量

归并求逆序数 &amp;&amp; 线段树求逆序数

Brainman Time Limit: 1000 MS Memory Limit: 30000 KB 64-bit integer IO format: %I64d , %I64u   Java class name: Main [Submit] [Status] [Discuss] Description Background Raymond Babbitt drives his brother Charlie mad. Recently Raymond counted 246 toothp

(中等) POJ 2828 Buy Tickets , 逆序+线段树。

Description: Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue… The Lunar New Year was approaching, but unluckily the Little Cat still had schedules going here and there. Now, he h

POJ 2528 Mayor&#39;s posters(线段树区间染色+离散化或倒序更新)

Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 59239   Accepted: 17157 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral post

POJ - 2528 - Mayor&#39;s posters 【线段树+离散化+补点】

http://poj.org/problem?id=2528 #include <cstdio> #include <iostream> #include <set> #include <cstring> #include <string> #define left rt<<1 #define right rt<<1|1 using namespace std; const int MAXN = 32768 + 5; in

POJ 2528 Mayor&#39;s posters (hash+线段树成段更新)

题意:有一面墙,被等分为1QW份,一份的宽度为一个单位宽度.现在往墙上贴N张海报,每张海报的宽度是任意的,但是必定是单位宽度的整数倍,且<=1QW.后贴的海报若与先贴的海报有交集,后贴的海报必定会全部或局部覆盖先贴的海报.现在给出每张海报所贴的位置(左端位置和右端位置),问张贴完N张海报后,还能看见多少张海报?(PS:看见一部分也算看到.) 思路:简单的成段更新,但是数据量是1千万,会MT,所以要区间压缩(离散化),保证覆盖的关系不变,离散化的时候有个易错的细节,poj数据水了,这个易错点引用h