归并排序求逆序数(POJ - 2299)

归并排序是将数列a[l,h]分成两半a[l,mid]和a[mid+1,h]分别进行归并排序,然后再将这两半合并起来。

在合并的过程中(设l<=i<=mid,mid+1<=j<=h),当a[i]<=a[j]时,并不产生逆序数;当a[i]>a[j]时,在

前半部分中比a[i]大的数都比a[j]大,将a[j]放在a[i]前面的话,逆序数要加上mid+1-i。因此,可以在归并

排序中的合并过程中计算逆序数.复杂度为nlogn.树状数组也可以求.以后再补充。。。

代码:

 

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
#define ll long long
const int N = 5e5+5;
ll ans;
int a[N],tp[N],n;

void mg(int arr[],int l,int r){
    int m=(l+r)/2,i=l,j=m+1,k=1;
    while(i<=m&&j<=r){
        if(arr[i]<=arr[j]){
            tp[k++]=arr[i++];
        }else {
            ans+=(m-i+1);
            tp[k++]=arr[j++];
        }
    }
    while(i<=m) tp[k++]=arr[i++];
    while(j<=r) tp[k++]=arr[j++];
    for(int i=1;i<k;i++)
        arr[l++]=tp[i];
}

void mgsort(int arr[],int l,int r){
    if(l>=r) return ;
    else {
        int m=(l+r)/2;
        mgsort(arr,l,m);
        mgsort(arr,m+1,r);
        mg(arr,l,r);
    }
}

int main(){
    while(~scanf("%d",&n)&&n){
        ans=0;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        mgsort(a,1,n);
        printf("%lld\n",ans);
    }
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值