超车(求逆序对个数)

  jzabc除了对多米诺骨牌感兴趣外,对赛车也很感兴趣。上个周末他观看了一场赛车比赛。他总是能想出许多稀奇的问题。某一时刻,他看到有n辆车(总是匀速行驶)在同一直线上,并且处在一个无限长度的直道上,而且n辆车有严格的先后之分。他通过特殊的器材测出了每一辆车的速度。那么问题出现了,如果有两辆车A车和B车,A车在B车的后面,并且A车的速度比B车的快,那么经过一段时间后,A车一定会超过B车。我们称之为一次超车。那么他想请你帮忙计算超车总数。我们记车道起点的坐标为0。没有两辆车的坐标相同。

输入格式:

第一行,一个数n,车辆总数。
第二行至第n+1行,为n辆车的信息
每行有两个正整数x,y,x和y之间有一个空格
x为车的坐标,y为车的速度
0<x,y<=1000000000,

输出格式:

一行,超车总数。

样例输入:

2
5 6
2 8

样例输出:
1

题解:

这道题其实就是求逆序对的个数

因为没有两辆车的坐标相同,所以可以先对坐标排序,然后求速度的逆序对个数,就是超车数

=============分割线==============

方法有两个,一个是利用归并排序,排序的次数就是逆序对的个数

还有一个貌似是使用树状数组,有时间再试试吧...

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n;
long long temp[310000],ans=0;//temp用作存储临时的数据

struct str
{
    long long coo,spe;
}a[310000];

bool cmp(str a,str b)
{
    return a.coo<b.coo;
}

void merge_array(int x,int y)//合并两个数组
{
    int i=x;
    int mid=(x+y)/2;
    int j=mid+1;
    int k=x;
    
    while(i<=mid && j<=y)
    {
        if(a[i].spe>a[j].spe)
        {
            temp[k++]=a[j++].spe;
            ans+=mid-i+1;  //a[i..mid]已经有序了,那么a[i+1], a[i+2], ... a[mid]都是大于a[j]的,
        }
        else
            temp[k++]=a[i++].spe;
    }
    
    while(i<=mid)
        temp[k++]=a[i++].spe;
    
    while(j<=y)
        temp[k++]=a[j++].spe;
    
    for(int i=x;i<=y;i++)  
        a[i].spe=temp[i];  
}

void merge_sort(int x,int y)
{
    if(x<y)
    {
        int mid=(x+y)/2;
        merge_sort(x,mid);
        merge_sort(mid+1,y);
        merge_array(x,y);
    }
}

int main()
{
    ios::sync_with_stdio(false);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i].coo>>a[i].spe;
    sort(a+1,a+1+n,cmp);
    merge_sort(1,n);
    cout<<ans<<endl;
    
    return 0;
}
原文地址:https://www.cnblogs.com/kekit/p/6483224.html