/*
HDU1394 利用线段树求逆序对数
方法:
从1……n插入每个数,每插入一个数,计算当前线段树中数为a[i]+1....maxval的数有多少个,特别需要当心a[i]+1有可能大于maxval的情况
交换两个相邻数,逆序数+1或-1, 交换两个不相邻数a, b, 逆序数+=两者间大于a的个数-两者间小于a的个数
对于本题,可以假设在第n+1个位置上有一个数n,每次将第一个数与第n+1位置上的n互换
逆元对数 = 原逆元对数 - 比该位置数小的个数 + 比该位置大的个数
*/
//4673112 2011-09-28 18:46:40 Accepted 1394 78MS 240K 1470 B G++ nkhelloworld
//4673116 2011-09-28 18:47:06 Accepted 1394 46MS 280K 1470 B C++ nkhelloworld
#include <cstdio>
#define MAXN 5000
struct SEGMENTTREE
{
    int lt,rt,val;
}tree[MAXN*4];
int n,a[MAXN+1];

void buildsegtree(int root,int lt,int rt)
{
    tree[root].lt = lt; tree[root].rt = rt; tree[root].val = 0;
    if(lt == rt)    return ;
    int mid = (lt+rt)>>1;
    buildsegtree(root<<1,lt,mid);
    buildsegtree(root<<1|1,mid+1,rt);
}

int query(int root,int lt,int rt)
{
    if(tree[root].lt == lt && tree[root].rt == rt)
        return tree[root].val;
    int mid = (tree[root].lt + tree[root].rt)>>1;
    if(rt <= mid)
        return query(root<<1,lt,rt);
    if(lt>mid)
        return query(root<<1|1,lt,rt);
    return query(root<<1,lt,mid) + query(root<<1|1,mid+1,rt);
}

void update(int root,int pos)
{
    tree[root].val ++;
    if(tree[root].lt == tree[root].rt)
        return ;
    int mid = (tree[root].lt + tree[root].rt)>>1;
    if(pos <= mid)
        update(root<<1,pos);
    else
        update(root<<1|1,pos);
}

int main()
{
    int i,sum,minn;
    while(scanf("%d",&n)!=EOF)
    {
        sum = 0;
        buildsegtree(1,0,n-1);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            sum += query(1,a[i],n-1);
            update(1,a[i]);
        }
        minn = sum;
        for(i=1;i<=n;i++)
        {
            sum = sum - a[i] + (n - a[i] - 1);
            if(sum < minn)  minn = sum;
        }
        printf("%d\n",minn);
    }
    return 0;
}

posted on 2011-09-28 19:03  NKHe!!oWor!d  阅读(359)  评论(0编辑  收藏  举报