POJ 2299 Ultra-QuickSort(归并排序,树状数组,离散化)

http://poj.org/problem?id=2299

Ultra-QuickSort
Time Limit: 7000MS Memory Limit: 65536K
Total Submissions: 55702 Accepted: 20570

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

题意:

给定一段序列,问最少需要交换多少次使其变为升序。


思路:

一看题意,铁定的冒泡排序,再一看数据范围,挺大的,注定超时。

其实题目给的好好的,学习新的排序方法,翻了下下个学期的教材,提前了解下归并排序。

教材-> 《数据结构》人民邮电出版社,严蔚敏编著第二版。

其实,首次接触归并,看了一下午还没看出什么,先敲个树状数组的。


用树状数组 AC 后Code 1,再写一次归并排序吧 Code 2。

题目不错,还有前天宇神讲的离散化操作。

树状数组参考自CSDN-----初始化树状数组,从头到尾读入这些数,每读入一个数就更新树状数组,

查看它前面比它小的已出现过的有多少个数记为 ans,

然后用当前位置减去该 ans,就可得到当前数导致的逆序对数

把所有的加起来就是总的逆序对数。问题是数字虽然唯一,但是是数据范围大,需要离散化处理。


Code 1 --树状数组:

7644K 391MS

#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
typedef __int64 LL;
const int MYDD=1103+5e5;

/* 离散化操作 */
int reflect[MYDD];//存放离散化操作后的值
struct Q {//离散化记录元素元素大小和位置
	int ori_value;//original
	int ori_position;
} node[MYDD];
bool cmp_val(Q x,Q y) {//结构体按照value的大小升序
	return x.ori_value<y.ori_value;//不知道是不是神经蛋一样,今天总忘记 retrun 
}
/* 树状数组操作 */
int tree[MYDD];
int LowBit(int x) {
	return (-x)&x;
}

void UpDate(int x,int value,int n) {
	while(x<=n) {
		tree[x]+=value;
		x+=LowBit(x);
	}
}

int GetSum(int x) {
	int ans=0;
	while(x>0) {
		ans+=tree[x];
		x-=LowBit(x);
	}
	return ans;
}

int main() {
	int n;
	while(scanf("%d",&n)&&n) {
		for(int j=1; j<=n; j++) {
			scanf("%d",&node[j].ori_value);
			node[j].ori_position=j;
		}
		
		sort(node+1,node+1+n,cmp_val);
		for(int j=1; j<=n; j++) {//离散化
			reflect[node[j].ori_position]=j;
		}

		LL ans=0;
		memset(tree,0,sizeof(tree));
		for(int j=1; j<=n; j++) {
			UpDate(reflect[j],1,n);
			ans=ans+j-GetSum(reflect[j]);
		}
		printf("%I64d\n",ans);
	}
	return 0;
}

Code 2:归并排序
3912K 391MS

#include<stdio.h>
#include<cstring>
typedef __int64 LL;
const int MYDD=1103+5e5;

LL ans;
int a[MYDD],b[MYDD];
void Merge(int low,int mid,int high) {	//将无序表啊 a[]归并到 b[]
	int i=low,j=mid+1,t=0;	//*wa_note i=1
	while(i<=mid&&j<=high) {	//将 a[]中记录由小到大归并到 b[]中 
		if(a[i]>a[j]) {
			b[t++]=a[j++];
			ans+=mid-i+1;
		} else {
			b[t++]=a[i++];
		}
	}
	while(i<=mid)
		b[t++]=a[i++];	//剩余的a[low...mid]赋值到 b[] 中 
	while(j<=high)
		b[t++]=a[j++];	//剩余的a[j...high]赋值到 b[] 中 
	for(int j=0; j<t;j++)
		a[low+j]=b[j];	//*wa_note a[low+i]=b[i]
}


void MergingSort(int low,int high) {
	if(low<high) {
		int mid=(low+high)/2;//当前序列一分为二 
		MergingSort(low,mid);//对子序列进行递归归并 
		MergingSort(mid+1,high);
		Merge(low,mid,high);//将以上两个序列归并到 b[] 
	}
}

int main() {
	int n;
	while(scanf("%d",&n)&&n) {
		ans=0;
		for(int j=0; j<n; j++)	scanf("%d",&a[j]);

		MergingSort(0,n-1);//归并排序 
		printf("%I64d\n",ans);
	}
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值