hdu 1394 Minimum Inversion Number【线段树,单点增减,区间求和】

题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=1394

题意:给出一个长度为n的序列,0 ~ n-1,对序列可以转换成 :

1 ,... , n-1, 0

2, ... , n-1, 0, 1

...

n-1, 0, 1, ..., n-2

在这些序列中找到一个序列,是这个序列的逆序数是最小的。输出逆序数的个数。

分析思路:http://wenku.baidu.com/view/6e02b7492e3f5727a5e9623f.html

代码:

#include<stdio.h>

#define MAXN 5001

int tree[MAXN << 2]; 

void PushUP(int rt)
{
	tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}

void build(int l, int r, int rt)
{
	tree[rt] = 0;
	if( l == r ) {
		return ;
	}
	int mid = (l + r) >> 1;
	build(l, mid, rt << 1);
	build(mid + 1, r, rt << 1 | 1);
}

void update(int p, int l, int r, int rt)
{
	if(l == r) {
		tree[rt] += 1;
		return ;
	}
	int mid = (l + r) >> 1;
	if(p <= mid) {
		update(p, l, mid, rt << 1);
	} else {
		update(p, mid + 1, r, rt << 1 | 1);
	}
	PushUP(rt);
}

int query(int L, int R, int l, int r, int rt)
{
	if(L <= l && R >= r) {
		return tree[rt];
	}
	int ans = 0;
	int mid = (l + r) >> 1;
	if(L <= mid) {
		ans += query(L, R, l, mid, rt << 1);
	}
	if(R > mid) {
		ans += query(L, R, mid + 1, r, rt << 1 | 1);
	}
	return ans;
}

int a[MAXN];
int main()
{
	int n;
	while(scanf("%d", &n) != EOF) {
		build(0, n-1, 1);
		int sum = 0;
		for(int i = 0; i < n; i++) {
			scanf("%d", &a[i]);
			sum += query(a[i], n-1, 0, n-1, 1);
			update(a[i], 0, n-1, 1);
		}
		int ans = sum;
		for(int i = 0; i < n; i++) {
			//在序列中比a[i]小的数的个数是 a[i];
			//比a[i]大的数的个数是 n - a[i] - 1;
			sum = sum - ( a[i] ) + ( n - a[i] - 1 );
			ans = ans > sum ? sum : ans;
		}
		printf("%d\n", ans);
	}
	return 0;
}

  

posted @ 2012-10-30 14:14  小猴子、  阅读(217)  评论(0)    收藏  举报