Ultra-QuickSort(逆序数)

来源:互联网 发布:词典推荐 知乎 魏 编辑:程序博客网 时间:2024/06/09 00:05

      
                                                                                                                                               Ultra-QuickSort
Time Limit: 7000MS Memory Limit: 65536KTotal Submissions: 62759 Accepted: 23385

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

59105431230

Sample Output

60
题意是求一组数的逆序数,首先搞清楚逆序数是什么,即一组数中逆序对的个数,如 3,4,5,1中逆序对为(3,1),(4,1),所以逆序数为2。
求逆序数的方法:用树状数组,用从c[]表示树状数组,组用setsum(i)函数求当前序列中小于等于i的数的个数,用i-getsum(i)得到i前面比i大的数。重点是为什么getsum(i)表示i前面比i小的数的个数呢??前面明明用此函数求前i项数的和,此题先把c[]全设值为0,由于数是不重复的,我们把读入数x时设置第x这个位置的值为1,c[x]=1,当读入第二个数y时,把在第y个位置的数为1,即c[y],如果y比x大,肯定c[y]在从c[x]后面,这样就c[y]前就有一个1,就是有一个比自己小的数,就会在这样可以无形得到一个有顺序(从小到大)的序列。 比如给出一组数  5 3 6 2 1,读入第一个数此时得到c是 0 0 0 1 0;读入3时,c为0 0 1 1 0;读入6时 c为 0 0 1 1 1, 发现当时读入的1的位置前面出现的1的个数就是比自己小的数的个数
于是得到代码:
#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#define ll long long#define maxn 100005using namespace std;int c[maxn],n;int low_bit(int i){    return i&(-i);}void update(int i,int v){    while(i<=n){        c[i]+=v;        i+=low_bit(i);    }}//前i项中比i小的数的个数int get_sum(int i){    int res=0;    while(i){        res+=c[i];        i-=low_bit(i);    }    return res;}int main(){    while(scanf("%d",&n),n)    {        memset(c,0,sizeof(c));        int ans=0;        for(int i=1;i<=n;i++)        {            int a;            scanf("%d",&a);            update(i,1);            ans+=i-get_sum(a);        }        printf("%d\n",ans);    }    return 0;}

但是由上面我们知道c[]中放的是输入变量,此题数值较大,直接开数组肯定不行,但n的值较小,于是我们把它离散化。
假如现在有一些数:1234 98756 123456 99999 56782,由于1234是第一小的数,所以reflct[1]=1;依此,有reflect[5]=2,reflect[2]=3,reflect[4]=4,reflect[3]=5;这 样转化后并不影响原来数据的相对大小关系,且把c[]范围缩小了。
于是得到代码:
#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#include<iostream>using namespace std;const int N=500005;int c[N],reflect[N], n;struct node{    int val;    int pos;}nd[N];bool cmp(node p1,node p2){    return p1.val<p2.val;}int lowbit(int x){    return x&(-x);}int updata(int x){    while(x<=n)    {        c[x]+=1;        x+=lowbit(x);    }}int getsum(int x){    int ans=0;    while(x>0)    {        ans+=c[x];        x-=lowbit(x);    }    return ans;}int main(){    while(~scanf("%d",&n)&&n)    {        for(int i=1;i<=n;i++)        {            scanf("%d",&nd[i].val);            nd[i].pos=i;        }        sort(nd+1,nd+n+1,cmp);        for(int i=1;i<=n;i++)        reflect[nd[i].pos]=i;        for(int i=1;i<=n;i++) c[i]=0;        long long ans=0;        for(int i=1;i<=n;i++)        {            updata(nd[i].pos);            ans+=i-getsum(nd[i].pos);        }        printf("%lld\n",ans);    }}