杭电1394(线段树) Minimum Inversion Number

题意:输入一行数组,可以把数组的第一个挪到最后一位(藉此可以整出n个不同的数组),求这些数组中,最少的数组的逆序数对数。

提示:对于每个数组的逆序数,并不需要更改数组,只需要由上一个推下一个:下一个序列的逆序数 sum = 上一个的sum - a[i] - 1 - a[i]

代码:

#include<iostream>
#include<cstdio>
#define L(u) (u<<1)
#define R(u) (u<<1|1)
const int M = 5005;

struct Node
{
    int l,r,sum;
}node[M<<2];
int a[M];
int min (int a,int b)
{
    return a > b ? b : a;
}
void Build (int u,int left,int right)
{
    node[u].l = left,node[u].r = right;
    node[u].sum  = 0;
    if (node[u].l == node[u].r)
        return ;
    int mid = (node[u].l + node[u].r)>>1;
    Build (L(u),left,mid);
    Build (R(u),mid+1,right);
}
void Update(int u,int p)
{
    if (node[u].l == node[u].r){
        node[u].sum ++;
        return ;
    }
    if (p <= node[L(u)].r) Update(L(u),p);
    else Update(R(u),p);
    node[u].sum = node[L(u)].sum + node[R(u)].sum;   //向上更新
}
int Query(int u,int p) //查找区间p~n 
{
    if (p <= node[u].l)
        return node[u].sum;
    if (p <= node[L(u)].r)
        return Query(L(u),p) + Query(R(u),p);
    else return Query(R(u),p);
}
int main ()
{
    int n,i;
    while (~scanf ("%d",&n)) 
    {
        Build(1,0,n);
        int sum = 0;
        for (i = 0;i < n;i ++)
        {
            scanf ("%d",&a[i]);//输入数组 
            sum += Query(1,a[i]+1);//查找区间 
            Update(1,a[i]);
        }
        int ans = sum;
        for (i = 0;i < n;i ++)
        {
            sum += n - a[i] - a[i] - 1;
            ans = min(ans,sum);
        }
        printf ("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jack_jxnu/article/details/81290557