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

Ultra-QuickSort
Time Limit: 7000MS   Memory Limit: 65536K
Total Submissions: 55048   Accepted: 20256

Description

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
题意:就是求逆序数
分析:有几种方法,这里用了两个
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;

const int MAXN = 500010;
int F[MAXN];
int a[MAXN];
int n;
pair<int,int>p[MAXN];
void update(int x,int val)
{
    while(x<=n)
    {
        F[x]+=val;
        x+=x&-x;
    }
}
int query(int x)
{
    int res=0;
    while(x>0)
    {
        res+=F[x];
        x-=x&-x;
    }
    return res;
}

int main()
{
    while(scanf("%d",&n)==1&&n)
    {
        memset(F,0,sizeof(F));
        memset(a,0,sizeof(a));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&p[i].first);
            p[i].second=i;
        }
        sort(p+1,p+n+1);
        a[p[1].second]=1;
        for(int i=2;i<=n;i++)
        {
            if(p[i].first!=p[i-1].first) a[p[i].second]=i;
            else a[p[i].second]=a[p[i-1].second];
        }
        long long ans=0;
        for(int i=1;i<=n;i++)
        {
            update(a[i],1);
            ans+=query(n)-query(a[i]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}
/*
 用归并排序求逆序数
 */
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;

const int MAXN = 500010;
int a[MAXN],b[MAXN],c[MAXN];
long long ans;

//将已经排好的l-mid,mid+1-r进行归并
void merge(int *a,int l,int mid,int r)
{
    for(int i=0,j=l;j<=mid;j++)
        b[i++]=a[j];
    int len1=mid-l+1;
    for(int i=0,j=mid+1;j<=r;j++)
        c[i++]=a[j];
    int len2=r-mid;
    int i=0,j=0,k=l;
    while(i<len1&&j<len2&&k<=r)
    {
        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 l,int r)
{
    if(l<r)
    {
        int mid=(l+r)/2;
        merge_sort(a,l,mid);
        merge_sort(a,mid+1,r);
        merge(a,l,mid,r);
    }
}

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

 

 
posted @ 2016-08-05 19:51  季末Despair  阅读(194)  评论(0编辑  收藏  举报