HDU 1394 Minimum Inversion Number

  线段树的一个应用,求逆序数。思路为sum[i]0代表i未出现,为1则已经出现,

然后查询时我们只要统计新加入的数到n-1这个范围内有多少个sum[i]1,也就是当前

数的逆序,然后累加,就是我们要求的逆序数。因为其他形式都可以由第一次求得的逆

序数递推而来,所以只需计算一次。

 

/*2012-08-07 16:54:38    Accepted    1394    78MS    252K    1478 B    G++    Yu*/

#include<stdio.h>

#include<algorithm>

using namespace std;



#define lson l, m, rt << 1

#define rson m + 1, r, rt << 1 | 1



const int MAXN = 5050;

int sum[MAXN << 2];

int n, x[MAXN];



void PushUp(int rt)

{

    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];

}



void build(int l, int r, int rt)

{

    int m = l + r >> 1;

    sum[rt] = 0;

    if(l == r) return;

    build(lson);

    build(rson);

    PushUp(rt);

}



void update(int p, int l, int r, int rt)

{

    int m = l + r >> 1;

    if(l == r)

    {

        sum[rt] ++;

        return;

    }

    if(p <= m) update(p, lson);

    else update(p, rson);

    PushUp(rt);

}



int query(int L, int R, int l, int r, int rt)

{

    int m = l + r >> 1, ret = 0;

    if(L <= l && r <= R)

    {

        return sum[rt];

    }

    if(L <= m) ret += query(L, R, lson);

    if(R > m) ret += query(L, R, rson);

    return ret;

}



int main()

{

    int i, ans, ret;

    while(scanf("%d", &n) == 1)

    {

        build(0, n - 1, 1);

        ans = 0;

        for(i = 0; i < n; i ++)

        {

            scanf("%d", &x[i]);

            ans += query(x[i], n - 1, 0, n - 1, 1);

            //查询在x[i]之前比它大的数的个数,累加。

            update(x[i], 0, n - 1, 1);

        }

        ret = 0x3f3f3f3f;

        for(i = 0; i < n; i ++)

        {

            ans += n - x[i] - x[i] - 1;

            ret = min(ret, ans);

        }

        printf("%d\n", ret);

    }

    return 0;

}

 

 

 

你可能感兴趣的:(version)