hdu 1394 Minimum Inversion Number(单点更新,区间求和)

给n个数组成的序列,由0~n-1构成。每次把第一个数移动到最后一个数,可以形成一个新的序列。总共可形成n个序列,求这n个序列中最小的逆序数。

 

先求原始序列的逆序数个数:每输入一个数,统计其之前的比它大的数的个数。这里用线段树记录区间内数的个数。

对于每一个数,将其挪到后面之后,新的序列的逆序数个数=原序列逆序数个数-比该数小的数个数+比该数大的数的个数。

 

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define maxn 5005
#define lson i<<1,l,m
#define rson i<<1|1,m+1,r
int sum[maxn<<2],x[maxn];
void PushUp(int i)
{
    sum[i]=sum[i<<1]+sum[i<<1|1];
}
void build(int i,int l,int r)
{
    sum[i]=0;
    if(l==r) return;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
void update(int num,int i,int l,int r)
{
    if(l==r) {sum[i]++;return;}
    int m=(l+r)>>1;
    if(num<=m) update(num,lson);
    else update(num,rson);
    PushUp(i);
}
int query(int L,int R,int i,int l,int r)
{
    if(L<=l&&r<=R) return sum[i];
    int m=(l+r)>>1;
    int ans=0;
    if(L<=m) ans+=query(L,R,lson);
    if(R>m) ans+=query(L,R,rson);
    return ans;
}
int main()
{
    int n,i;
    while(~scanf("%d",&n))
    {
        build(1,0,n-1);
        int s=0;
        for(i=0;i<n;++i)
        {
            scanf("%d",&x[i]);
            s+=query(x[i],n-1,1,0,n-1);
            update(x[i],1,0,n-1);
        }
        int ans=s;
        for(i=0;i<n;++i)
        {
            s=s-x[i]+n-x[i]-1;
            ans=min(ans,s);
        }
        printf("%d\n",ans);
    }
    return 0;
}


 

你可能感兴趣的:(hdu 1394 Minimum Inversion Number(单点更新,区间求和))