poj 2299 Ultra-QuickSort(树状数组-改上求下+改下求上||归并排序)

来源:互联网 发布:微艾薇h5建站 编辑:程序博客网 时间:2024/06/06 11:04

Ultra-QuickSort
Time Limit: 7000MS Memory Limit: 65536KTotal Submissions: 60497 Accepted: 22431

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

归并排序,或用树状数组记录,先写树状数组

1:树状数组,对于题目来说 999,999,999的数据范围,开数组肯定要爆内存,由于n只有500000,可以对数据离散化一下,把每个数据改成1~n之间的数,拿第一组数据来说,9最大,9的角标为1,所以让a[1]=5;

先上个改上界,求下界的码,不太好看懂,感觉有点绕;

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define maxn 500010typedef long long LL;struct node{    int x,pos;}q[maxn];int a[maxn],num[maxn];int n;int lowbit(int x){    return x&-x;}bool cmp(node s,node b){    return s.x<b.x;}void add(int i,int x){    while(i<=n)    {        a[i]+=x;        i+=lowbit(i);    }}int getsum(int i){    int sum=0;    while(i>0)    {        sum+=a[i];        i-=lowbit(i);    }    return sum;}int main(){    while(~scanf("%d",&n),n)    {        memset(a,0,sizeof(a));//注意清零        for(int i=1;i<=n;++i)        {            scanf("%d",&q[i].x);            q[i].pos=i;//记录原始的位置        }        sort(q+1,q+n+1,cmp);        for(int i=1;i<=n;++i)            num[q[i].pos]=i;//离散化        LL ans=0;        for(int i=1;i<=n;++i)        {            ans+=(i-1)-getsum(num[i]);//前面有i-1个数,getsum(num[i])为小于num[i]的数            add(num[i],1);//加入数组中        }        printf("%lld\n",ans);    }    return 0;}

下面是自己改的,改下界求上界的码,个人感觉很简洁

既然每次更新的是1~a[i]之间<=a[i]的个数,那么我读取的时候直接读a[i]~n不就是a[i]~n之间>=a[i]的值吗?

关于相等的情况:会有这样一个问题,读取的时候为什么不是a[i]~n之间>=a[i],那么如果出现两个值相等的情况呢?,我考虑了很久关于这个问题,其实没必要,假如出现几个数相等的情况,但经过离散化之后,他们所储存的值是不相等的,原本位置靠后的快排后位置相较于几个相等的值,它依然靠后,这就保证了一个值更新时不会影响后面和这个值相等的值的读取,举个例子:

比如有这样几个数 :1,2,5,5

               离散后  a:1,2,3,4;

更新i=1,2时暂且不谈,

read求和是对a[i]~n;

i=3,ans+read(a[3])  求和3~n           然后更新3,更新3时,更新的是1~3,也就是小于等于a[3]的

i=4,ans+read(a[4])  求和4~n           然后更新4,会发现位置3和位置4都是5,但更新时并没有影响

至于add为什么放后面,因为最后一个数的逆序数一定是0,不需要读取,少读取一次

#include <iostream>#include <iomanip>#include<stdio.h>#include<string.h>#include<stack>#include<stdlib.h>#include<queue>#include<map>#include<math.h>#include<algorithm>#include<vector>#define mem(a,b) memset(a,b,sizeof(a))#define ll long long#define maxn  500005using namespace std;int n;struct node{    int val,pos;}e[maxn];int t[maxn],a[maxn];bool cmp(node a,node b){    return a.val<b.val;}int lowbit(int x){    return x&-x;}void add(int x,int num){    for(int i=x;i>0;i-=lowbit(i))    {        t[i]+=num;    }}int read(int x){    int sum=0;    for(int i=x;i<=n;i+=lowbit(i))        sum+=t[i];    return sum;}int main(){    while(~scanf("%d",&n),n)    {        mem(t,0);        for(int i=1;i<=n;i++)        {            scanf("%d",&e[i].val);            e[i].pos=i;        }        sort(e+1,e+1+n,cmp);       for(int i=1;i<=n;i++)        a[e[i].pos]=i;        ll ans=0;        for(int i=1;i<=n;i++)       {           ans+=read(a[i]);           //每次加上i~n之间小于a[i]的个数           add(a[i],1);           //更新1~i之间<=a[i]的个数            }        printf("%lld\n",ans);    }    return 0;}
再敲一遍归并排序的模板

#include <iostream>#include <iomanip>#include<stdio.h>#include<string.h>#include<stack>#include<stdlib.h>#include<queue>#include<map>#include<math.h>#include<algorithm>#include<vector>#define mem(a,b) memset(a,b,sizeof(a))#define ll long long#define maxn  500005using namespace std;int a[maxn],c[maxn];ll cnt;void Merge(int a[],int first,int mid,int last,int c[]){    int i=first,j=mid+1;    int m=mid,n=last;    int k=0;    while(i<=m||j<=n)    {        if(j>n||(i<=m&&a[i]<=a[j]))        {            c[k++]=a[i++];        }        else        {            c[k++]=a[j++];            cnt+=(m-i+1);        }    }    for(i=0;i<k;i++)        a[first+i]=c[i];}void merge_sort(int a[],int first,int last,int c[]){    if(first<last)    {        int mid=(first+last)/2;        merge_sort(a,first,mid,c);        merge_sort(a,mid+1,last,c);        Merge(a,first,mid,last,c);    }}int main(){    int n;    while(~scanf("%d",&n),n)    {        mem(c,0);        cnt=0;        for(int i=0;i<n;i++)            scanf("%d",&a[i]);        merge_sort(a,0,n-1,c);        printf("%lld\n",cnt);    }    return 0;}






0 0
原创粉丝点击