POJ 2299 Ultra-QuickSort

转载请注明出处忆梦http://blog.csdn.net/yimeng2013/article/details/13033965


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

题意:有n个数,进行升序排列,每次只能移动相邻的两个数,问最少需要操作多少次

题解:典型的树状数组求逆序数问题。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 500010
#define LL long long
LL n;
LL c[N];
LL f[N];
struct Node
{
	LL index;
	LL key;
}node[N];

LL lowbit(LL x)
{
	return x & -x;
}

LL sum(LL x)
{
	LL ret = 0;
	while(x > 0)
	{
		ret += c[x];
		x -= lowbit(x);
	}
	return ret;
}

void add(LL x,int d)
{
	while(x <= n)
	{
		c[x] += d;
		x += lowbit(x);
	}
}

LL cmp(Node a, Node b)
{
	return a.key < b.key;
}

int main ()
{
	while(scanf("%lld", &n) , n)
	{
		memset(c, 0, sizeof(c));
		memset(f, 0, sizeof(f));

		for(int i = 1; i <= n; i++)
		{
			scanf("%lld", &node[i].key);
			node[i].index = i;
		}
		sort(node+1, node+1+n, cmp);
		

		//相当于将原序列的每一个数标记上了大小的序号
		for(int i = 1; i <= n; i++)
			f[node[i].index] = i;

		long long  ans = 0;
		//从n~1,求的是每一个数的前面有几个比他大的数
		//而从1~n则表示每一个数的前面有几个比他小的数
		for(int i = n; i >= 1; i--)
		{
			add(f[i], 1);
			ans += sum(f[i]-1);
		}
		printf("%lld\n", ans);
	}
	return 0;
}



你可能感兴趣的:(树状数组)