【树状数组】 poj2299 Ultra-QuickSort

Ultra-QuickSort 

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

题意:给n个数字,每次只能交换相邻两个数字,问最少需要交换多少次可以将n个数字从小到大排序

题解:可以通过模拟冒泡排序发现,对于每个数字,要把它交换到排序后对应的位置,交换次数就等于它的逆序数,即题目等价于求逆序数。

逆序数定义:在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数

代码:

#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define lowbit(x) ((x)&(-(x)))
#define LL long long
LL c[500005],b[500005];//c存和,b存逆序数
int n;
struct node
{
	int value,num;
}arr[500005];
bool cmp(node x,node y)
{
	return x.value<y.value;
}
LL getsum(int pos)
{
    int x=pos;
    LL sum=0;
    for(;x>0;x-=lowbit(x))
        sum+=c[x];
    return sum;
}
void update(int pos,int value) //更新pos的值
{
    int x=pos;
    for(;x<=n;x+=lowbit(x))
        c[x]+=value;
}
int main()
{
	for(;scanf("%d",&n)&&n;)
	{
		memset(c,0,sizeof(c));
                for(int i=1;i<=n;i++)
		{
			scanf("%d",&arr[i].value);
			arr[i].num=i;
		}
		sort(arr+1,arr+1+n,cmp);
		for(int i=1;i<=n;i++)
		{
			arr[arr[i].num].value=i;//离散化
		}
		for(int i=1;i<=n;i++)
		{
			update(arr[i].value,1);
			b[i]=i-getsum(arr[i].value);
		}
		__int64 ans=0;
		for(int i=1;i<=n;++i)
			ans+=b[i];
		printf("%I64d\n",ans);
	}
	return 0;
}
来源: http://blog.csdn.net/ACM_Ted

你可能感兴趣的:(c)