IT民工
加油!

  线段树的一个应用,求逆序数。思路为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;
}

 

 

 

posted on 2012-08-07 17:02  找回失去的  阅读(190)  评论(0)    收藏  举报