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

Ultra-QuickSort
Time Limit: 7000MS Memory Limit: 65536K
Total 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

5
9
1
0
5
4
3
1
2
3
0

Sample Output

6
0
/*
之前用归并排序做,竟然超时。。。。很郁闷,明明可以的,,我也没再写归并排序,这个事树状数组做的、
加油!!!
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;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值