归并排序求逆序对 //(洛谷)U4566 赛车比赛
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了归并排序求逆序对 //(洛谷)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; }
以上是关于归并排序求逆序对 //(洛谷)U4566 赛车比赛的主要内容,如果未能解决你的问题,请参考以下文章