poj 2299 Ultra-QuickSort 求逆序数,树状数组解法,详细解析

154 篇文章 1 订阅
7 篇文章 0 订阅
Ultra-QuickSort
Time Limit: 7000MS Memory Limit: 65536K
Total Submissions: 44554 Accepted: 16195

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
 
我的AC状态:	
 
	哈哈,时间连题目要求的十分之一都没到,我对树状数组还是很满意的。
	我先简单的说下树状数组求逆序数的方法,先逆序数定义:点击打开链接
看完逆序数的定义,首先从定义上看,我们其实可以转换一下,有一个序列An,假设其中第i数它后面有Ci比他小的,那逆序数就等于C=C1+C2+...Ci+...Cn,他其实就等价于假设其中第i个数,他前面有Di个比他大的数,D=D1+D2+...+Di+...+Dn=C。这个很容易理解的,相信大家都可以看懂。
接下来大家可能认为结束了,很显然,没结束,想一下树状数组的结构,如果求一个数前面有多少个比他大的,他得一直从1一直遍历到无穷。想想都可怕,所以我们得再转换一下,我们是否可以先求出前i个数中有多少个不大于第i个数的呢?这个很简单,我们只要遍历1->i,就解决了,那好,总共有i个数,假设在它前面有x个不大于第i数的,那比第i个数的大的自然不就出来了么,不就等于i-x-1吗?
	好了,分析到这里,我想大家都应该明白了,我得申明一下,树状数组不能直接求一个含有小于等于0的数的序列的逆序数,
至于为什么不能有负数,你想想,数组的下标能有负的吗?至于为什么不能有0,那是因为树状数组的有个0陷阱,这个自己百度,不多说了。
	不能直接求,但我们可以间接求啊,至于怎么求,我只简单的说一下,转换坐标轴的原点不就可以了吗!!假设10000>Ai>-10000,我们就可以把Ai+10000,得到20000<Ai+10000<0,你看,这样问题是不是就变成我们会的了!我不知道其他人是不是这样处理,这是我自己想的方法,其他人处理的方法估计和我的不会差太多的,毕竟这么简单,
好的,下面是我的代码:
 
#include <stdio.h>
#include <string.h>
#define MAX 1001000

int t[MAX];
int lowbit(int x)
{
	return x&(-x) ;
}

void update(int pos)
{
	while(pos<MAX)
	{
		++t[pos] ;
		pos += lowbit(pos) ;
	}
}

long long query(int pos)
{
	long long count = 0 ;
	while(pos>0)
	{
		count += t[pos] ;
		pos -= lowbit(pos) ;
	}
	return count ;
}

int main()
{
	int n;
	while(~scanf("%d",&n) && n)
	{
		memset(t,0,sizeof(t)) ;
		long long sum = 0 ;
		for(int i = 0 ; i < n ; ++i)
		{
			int temp ;
			scanf("%d",&temp) ;
			int count = query(temp+1) ;	//防止树状数组的0陷阱 
			sum += i-count ;
			update(temp+1) ;
		}
		printf("%I64d\n",sum) ;
	}
	return 0 ;
}

你看,,,是不是比归并排序求逆序数少很多代码,也更容易理解了!
辛辛苦苦码这么多字,,大家多支持一下啦
转载请标明出处
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值