HDU1394-Minimum Inversion Number(线段树单点更新)

题意:

给你一段序列a1,a2,a3,a4,a5,a6,a7,,然后这段序列可以一直调动第一个数字到最后,例如:

a2,a3,a4,a5,a6,a7,a1,…………直到循环了一遍。然后从这么多的序列中求出逆序列最小的一组。

每次循环的时候都可以递归求解逆序对数:设原序列逆序数为sum, 当把原序列第一个移动到最后位置时,逆序数变为:sum = sum-(ai-1)+(n-ai); 

所以只需要求最开始一段序列的逆序数,用线段树,复杂度O(NlogN)

线段树功能:update:单点增减 query:区间求和

//1120 KB 78 ms
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define root 0,n-1,1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
#define M 5005
int sum[M<<2];
int a[M];
void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
    if(l==r){
        sum[rt]=0;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
int query(int L,int R,int l,int r ,int rt)
{
    if(L<=l&&r<=R){
        return sum[rt];
    }
    int res=0;
    int m=(l+r)>>1;
    if(L<=m) res+=query(L,R,lson);
    if(R>m) res+=query(L,R,rson);
    return res;
}
void update(int pos,int l,int r,int rt)
{
    //printf("l=%d,r=%d\n",l,r);
    if(l==r) {
        sum[rt]++;
        return ;
    }
    int m=(l+r)>>1;
    if(pos<=m) update(pos,lson);
    else update( pos, rson);
    pushup(rt);
}
int main()
{
    int n;
    while(~scanf("%d",&n)){
        build(root);
        int ans=0,minn=(1<<30);
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
            ans+=query( a[i],n-1,root);
            update(a[i] ,root);

        }
        for(int i=0;i<n;i++){
            ans+=n-a[i]-1-a[i];
            minn=min(ans,minn);
        }
        printf("%d\n",minn);
    }
    return 0;
}


你可能感兴趣的:(HDU1394-Minimum Inversion Number(线段树单点更新))