POJ 2299 Ultra-QuickSort(求逆序数,归并排序或者离散化+树状数组)

Ultra-QuickSort
Time Limit: 7000MS   Memory Limit: 65536K
Total Submissions: 27665   Accepted: 9915

Description

POJ 2299 Ultra-QuickSort(求逆序数,归并排序或者离散化+树状数组)In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence
9 1 0 5 4 ,

Ultra-QuickSort produces the output
0 1 4 5 9 .

Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.

Input

The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.

Output

For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.

Sample Input

5

9

1

0

5

4

3

1

2

3

0

Sample Output

6

0

Source

 
 
本题就是求逆序数
 
一种方法是用归并排序求逆序数
 
/*

POJ 2299 Ultra-QuickSort

求逆序数

用归并排序求逆序数

*/

#include <stdio.h>

#include<string.h>

#include<iostream>

using namespace std;

const int MAXN=500010;

long long ans;//存放逆序数,比较大,必须用long long

int a[MAXN],b[MAXN],c[MAXN];



//将已经排好序的left~mid,mid+1~right进行归并

void merge(int *a,int left,int mid,int right)

{

    int i,j;

    i=0;

    for(j=left;j<=mid;j++)

       b[i++]=a[j];

    int len1=mid-left+1;

    i=0;

    for(j=mid+1;j<=right;j++)

       c[i++]=a[j];

    int len2=right-mid;

    i=0;

    j=0;

    int k=left;

    while(i<len1&&j<len2&&k<=right)

    {

        if(b[i]<=c[j])

        {

            a[k++]=b[i++];

        }

        else

        {

            a[k++]=c[j++];

            ans+=(len1-i);//逆序数就是累加后面比自己小的数的个数

            //此时b[i]>c[j],那么c[j]会给b[i]后面的len1-i个数造成逆序数

        }

    }

    while(i<len1) a[k++]=b[i++];

    while(j<len2) a[k++]=c[j++];

}

void merge_sort(int *a,int left,int right)//对a[left~right-1]进行归并排序

{

    if(left<right)

    {

        int mid=(left+right)/2;

        merge_sort(a,left,mid);

        merge_sort(a,mid+1,right);

        merge(a,left,mid,right);

    }

}

int main()

{

    //freopen("in.txt","r",stdin);

    //freopen("out.txt","w",stdout);

    int n;

    while(scanf("%d",&n),n)

    {

        for(int i=0;i<n;i++)

          scanf("%d",&a[i]);

        ans=0;

        merge_sort(a,0,n-1);

        printf("%I64d\n",ans);

    }

    return 0;

}

 

 

另外一种求逆序数的方法就是用树状数组。

本题数据比较大,需要先离散化,再用树状数组。

代码如下:

/*

POJ 2299 Ultra-QuickSort

求逆序数

离散化+树状数组

首先从小到大进行编号,从而实现离散化

然后利用树状数组来统计每个数前面比自己大的数的个数

*/



#include<stdio.h>

#include<string.h>

#include<algorithm>

#include<iostream>

using namespace std;

const int MAXN=500010;

int c[MAXN];

int b[MAXN];

int n;

struct Node

{

    int index;//序号

    int v;

}node[MAXN];

bool cmp(Node a,Node b)

{

    return a.v<b.v;

}

int lowbit(int x)

{

    return x&(-x);

}

void add(int i,int val)

{

    while(i<=n)

    {

        c[i]+=val;

        i+=lowbit(i);

    }

}

int sum(int i)

{

    int s=0;

    while(i>0)

    {

        s+=c[i];

        i-=lowbit(i);

    }

    return s;

}

int main()

{

   // freopen("in.txt","r",stdin);

    //freopen("out.txt","w",stdout);

    while(scanf("%d",&n),n)

    {

        for(int i=1;i<=n;i++)

        {

            scanf("%d",&node[i].v);

            node[i].index=i;

        }

        memset(b,0,sizeof(b));

        memset(c,0,sizeof(c));

        //离散化

        sort(node+1,node+n+1,cmp);

        //将最小的编号为1

        b[node[1].index]=1;

        for(int i=2;i<=n;i++)

        {

            if(node[i].v!=node[i-1].v) b[node[i].index]=i;

            else b[node[i].index]=b[node[i-1].index];

        }

        long long  ans=0;

        //这里用的很好

        //一开始c数组都是0,然后逐渐在b[i]处加上1;

        for(int i=1;i<=n;i++)

        {

            add(b[i],1);

            ans+=sum(n)-sum(b[i]);

        }

        printf("%I64d\n",ans);

    }

    return 0;

}

 

你可能感兴趣的:(Quicksort)