1. 程式人生 > >51Nod-1019 逆序數【逆序偶+歸併排序】

51Nod-1019 逆序數【逆序偶+歸併排序】

1019 逆序數 

在一個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為一個逆序。一個排列中逆序的總數就稱為這個排列的逆序數。

如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序數是4。給出一個整數序列,求該序列的逆序數。

Input

第1行:N,N為序列的長度(n <= 50000) 第2 - N + 1行:序列中的元素(0 <= A[i] <= 10^9) Output

輸出逆序數 Input示例

4 2 4 3 1 Output示例

4  

問題連結:51Nod-1019 逆序數

程式碼1(線段樹):

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=5e4+100;
#define ll long long
int a[maxn];
int x[maxn];
struct Tree
{
    int left,right;
    int val;

}tree[maxn<<2];
void build(int l,int r,int root)
{
    tree[root].left=l;
    tree[root].right=r;
    tree[root].val=0;
    if(l==r)
        return ;
    int mid=l+r>>1;
    build(l,mid,root<<1);
    build(mid+1,r,root<<1|1);

}
int query(int l,int r,int root)
{
    if(l==tree[root].left&&tree[root].right==r)
    {
        return tree[root].val;
    }
    int mid=tree[root].left+tree[root].right>>1;
    if(l>mid)
        return query(l,r,root<<1|1);
    else if(r<=mid)
        return query(l,r,root<<1);
    else
        return query(l,mid,root<<1)+query(mid+1,r,root<<1|1);
}
//包含id的區間都加1
void update(int id,int root)
{
    tree[root].val++;
    if(tree[root].left==tree[root].right)
    {
        return ;
    }
    int mid=tree[root].left+tree[root].right>>1;
    if(mid>=id) update(id,root<<1);
    else update(id,root<<1|1);

}
int Bin(int key,int n)
{
    int l=0;
    int r=n-1;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(x[mid]>key) r=mid-1;
        else if(x[mid]==key) return mid;
        else l=mid+1;
    }
    return 1;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
        x[i]=a[i];
    }
    sort(x,x+n);
    int m=1;
    for(int i=1;i<n;i++)
    {
        if(x[i]>x[m-1]) x[m++]=x[i];
    }

    build(1,50005,1);
    int sum=0;
    for(int i=0;i<n;i++)
    {
        int id=Bin(a[i],m)+1;
        sum+=query(id+1,50005,1);
        update(id,1);
    }
    printf("%d\n",sum);
    return 0;
}

解法2(歸併演算法):(拷了海島的程式碼)

/* 51Nod-1019  逆序數 */
 
#include <bits/stdc++.h>
 
using namespace std;
 
const int N = 50000;
int a[N], temp[N], cnt;
 
void merge(int low, int middle, int high)
{
    int i = low, j=middle+1, k = low;
    while(i <= middle && j <= high)
    {
        if(a[i] < a[j])
            temp[k++] = a[i++];
        else {
            cnt += j - k;
            temp[k++] = a[j++];
        }
    }
    while(i <= middle)
        temp[k++] = a[i++];
    while(j <= high)
        temp[k++] = a[j++];
    for(i=low; i<=high; i++)
         a[i] = temp[i];
}
 
void mergesort(int low, int high)
{
    if(low < high)
    {
        int middle = (low + high) / 2;
        mergesort(low, middle);
        mergesort(middle+1, high);
        merge(low, middle, high);
    }
}
 
int main()
{
    int n;
    while(~scanf("%d", &n)) {
        for(int i = 0; i < n; i++)
            scanf("%d", &a[i]);
 
        cnt = 0;
        mergesort(0, n - 1);
 
        printf("%d\n", cnt);
    }
 
    return 0;
}