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;
}

浙公网安备 33010602011771号