归并排序求逆序对 //(洛谷)U4566 赛车比赛

https://www.luogu.org/problem/show?pid=U4566

显然的逆序对,以前只是嘴巴ac,这次终于打了出来。

逆序对其实就是冒泡排序的排序次数。。。。但是一般的排序时间复杂度为O(n^2),于是都会想到归并排序。。。

一、二路归并

  已知两个有序数组,将其归并为一个有序数组

  很显然,将首元素比较,小的扔进目的数组,最后把剩下的扔进去。。

1 int a[n],b[m],tmp[n+m];
2 int i=1,j=1,k=1;
3 while(i<=n&&j<=m)
4 {
5     if(a[i]<a[j])    tmp[k++]=a[i++];
6     else    tmp[k++]=b[j++];
7 }
8 while(i<=n)    tmp[k++]=a[i++];
9 while(j<=m) tmp[k++]=a[j++];
二路归并

二、归并排序

  运用二路归并来排序,可以达到O(nlogn);

  首先对于无序数组分治,使以中点为界的两个部分都变成有序的,最后进行归并。

  代码见下。

三、利用归并排序求逆序对

  进行归并排序时,如果后面部分首元素小于前部分首元素,则与前部分所有元素产生逆序。。。

  如果小于不会有逆序;

 

 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<queue>
#define LL long long
#define for1(i,n,m) for(int i=(n);i<=(m);i++)
#define for2(i,n,m) for(int i=(n);i>=(m);i--)
#define Maxn 305000
#define Maxe 506000
#define Inf 0x7fffffff
using namespace std;
int a[Maxn],tmp[Maxn];
LL ans;
struct edge{
    int x,v;
};
edge e[Maxn];
void Msort(int L,int R)//对区间(L,R)归并排序 
{

    int mid;            
    if(L>=R)            
        return;        //边界 
    mid=(L+R)>>1;        //以中点分治 
    Msort(L,mid);        
    Msort(mid+1,R);        //对俩部分依次归并排序 
    int i=L,j=mid+1,k=L;    
    while(i<=mid&&j<=R)        //归并 
    {    
        if(a[i]>a[j])
        {
            tmp[k++]=a[j++];
            ans+=mid-i+1;    //求逆序对数,注意这里是减i,不是L; 
        }
        else
            tmp[k++]=a[i++];
    }
    while(i<=mid)    tmp[k++]=a[i++];
    while(j<=R)        tmp[k++]=a[j++];    //剩余的扔进辅助数组 
    for1(t,L,R)
        a[t]=tmp[t];                    //更改原数组 
    
}
bool cmp(const edge&q,const edge&w)
{
    return q.x<w.x;
}
int main()
{
    ios::sync_with_stdio(0);
    int n;
    cin>>n;
    for1(i,1,n)
    {
        cin>>e[i].x>>e[i].v;
    }
    sort(e+1,e+n+1,cmp);
    for1(i,1,n)
    {
        a[i]=e[i].v;
    }
    Msort(1,n);
    cout<<ans;
    return 0;
}
归并排序求逆序对

 

 

转载于:https://www.cnblogs.com/WMYWMY/p/6072347.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值