poj2299 Ultra-QuickSort&&NYOJ117 求逆序数 (树状数组求逆序对数+离散化)+(归并排序)

来源:互联网 发布:grace出血评分软件 编辑:程序博客网 时间:2024/05/16 14:07
Ultra-QuickSort
Time Limit: 7000MS Memory Limit: 65536KTotal Submissions: 42087 Accepted: 15296

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
/*之前用归并排序做,竟然超时。。。。很郁闷,明明可以的,,我也没再写归并排序,这个事树状数组做的、加油!!!Time:2014-9-2*/#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAX=500005;struct Node{int val;int pos;}node[MAX];int C[MAX],hash[MAX],N;bool cmp(const Node a,const Node b){if(a.val==b.val) return a.pos<b.pos;//因为位置从小到大开始检索,将位置大的放到后边避免重复   return a.val<b.val;//此处排序不能等于,如果值相等,位置按从小到大 }int lowbit(int x){return x&(-x);}void Modify(int x,int v){while(x<=N){C[x]+=v;x+=lowbit(x);}}int nSum(int x){int sum=0;while(x>0){sum+=C[x];x-=lowbit(x);}return sum;} void solve(){while(scanf("%d",&N),N){for(int i=1;i<=N;i++){scanf("%d",&node[i].val);node[i].pos=i;//标记值的位置 }sort(node+1,node+N+1,cmp);//值相等时,位置小的在前,检索的时候按位置从小到大检索,//如果位置从大到小,相同值的时候检索后边的时候会少掉前边的,这样求出来的i-nSum(hash[i])就会多一个,因为位置比它小的还没加到里边,树状数组是按位置来相加的 for(int i=1;i<=N;i++) hash[node[i].pos]=i;//将值位置标记为对应的hash值,将价值离散化,将把原来的位置按价值排序后的顺序进行标记,下边找逆序对的时候按原来的位置进行寻找 for(int i=1;i<=N;i++) C[i]=0;long long ans=0;for(int i=1;i<=N;i++){// i 表示位置,从第一个开始 Modify(hash[i],1); ans+=i-nSum(hash[i]);//排序方式可以使相同的值求逆序对为 0,将其减掉  //hash[i]表示第 i 个位置的hash值,用 i 减之前位置小于等于它的个数,就是比它大的个数 } printf("%lld\n",ans);}}int main(){solve();return 0;} 
/*以下为NYOJ117 的代码,代码一样很费解的是,昨天写的归并排序代码,超时。。。。至今不知道为什么Time:2014-9-3 0:09*/#include<cstdio>#include<cstring>#include<climits>#include<algorithm>using namespace std;const int MAX=500000+20;int a[MAX<<1],t1[MAX],t2[MAX];long long ans;void merge(int start,int end,int mid){int i,j,k;for(k=0,i=start;i<=mid;i++)t1[k++]=a[i];t1[k]=INT_MAX;for(k=0,i=mid+1;i<=end;i++)t2[k++]=a[i];t2[k]=INT_MAX;i=j=0;for(k=start;k<=end;k++){if(t1[i]<=t2[j]){a[k]=t1[i++];}else{ans+=(mid-start+1-i);a[k]=t2[j++];}}}void merge_sort(int start,int end){if(end>start){int mid=((start+end)>>1);merge_sort(start,mid);merge_sort(mid+1,end);merge(start,end,mid);}}void solve(){int T,N;scanf("%d",&T);while(T--){scanf("%d",&N);for(int i=0;i<N;i++)scanf("%d",&a[i]);ans=0;merge_sort(0,N-1);printf("%lld\n",ans);}} int main(){solve();return 0;} 

/*以下为超时代码,,我也不知道为什么。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。无语*/#include<stdio.h>#include<string.h>#include<limits.h> const int MAX=500020;long long cnt;int a[MAX<<1],t1[MAX],t2[MAX];void Merge(int start,int mid,int end){int i,j,k;for(k=0,i=0;i<=mid;i++)t1[k++]=a[i];t1[k]=INT_MAX;for(k=0,i=mid+1;i<=end;i++)t2[k++]=a[i];t2[k]=INT_MAX;//将前后的最后一个设成无穷大,到了最后一个如果没有合并完,会一直合并 for(i=j=0,k=start;k<=end;k++){if(t1[i]<=t2[j]){a[k]=t1[i++];}else{cnt+=(mid-start+1-i);a[k]=t2[j++];//如果前边比后边的大,由后边那个数与前边集合能组成的逆序对数为包括i--mid的个数 }}}void merge_Sort(int start,int end){if(end>start){int mid=(start+end)>>1;merge_Sort(start,mid);merge_Sort(mid+1,end);Merge(start,mid,end);}}void solve(){int T,N;scanf("%d",&T);while(T--){scanf("%d",&N);for(int i=0;i<N;i++)scanf("%d",&a[i]);cnt=0;merge_Sort(0,N-1);printf("%lld\n",cnt);}}int main(){solve();return 0;} 


0 0