您的位置:首页 > 其它

hdu 1394 Minimum Inversion Number

2014-01-04 00:36 351 查看
题意:按题意所诉规则得到若干序列,求这些序列中逆序数的最小值。

update:单点增减 , Queue:区间求和。

线段树的每一个节点记录的是在第i个数输入之前数列存在的区间的数字的数量

首先记录初始状态下的逆序数对的数量。

然后我们用递推:

当a0移到队末的时候,它比上一个序列多出来的是这个队列中比他大的,同时,又比它一个序列少 这个序列中比它小的数字的数量。

所以递推公式就是

sum = sum + (n-1-x[i]) - x[i];

因为它是连续的,所以第一个括号内的就是比它大的数,后面那个就是比它小的。

#include<cstdio>
#include<algorithm>
using namespace std;

#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
const int maxn = 5010;

int sum[maxn<<2];
int x[maxn];

void PushUP(int rt)
{
    sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}

void build(int l,int r,int rt)
{
    sum[rt]=0;
    if(l == r) return;
    int m = (l+r)>>1;
    build(lson);
    build(rson);
}

void Update(int val,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]++;
        return;
    }
    int m = (l+r)>>1;
    if(val <= m) Update(val,lson);
    else  Update(val,rson);
    PushUP(rt);
}

int Queue(int L,int R,int l,int r,int rt)
{
    if(L<=l && r<=R)
        return sum[rt];
    int m = (l+r)>>1;
    int res=0;
    if(L <= m) res += Queue(L ,R ,lson);
    if(R > m)  res += Queue(L ,R ,rson);
    return res;
}

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        build(0,n-1,1);
        int cnt=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&x[i]);
            cnt += Queue(x[i],n-1,0,n-1,1);
            Update(x[i],0,n-1,1);
        }
        int minc = cnt;
        for(int i=0;i<n;i++)
        {
            cnt += (n-1-x[i])-x[i];
            minc = min(minc,cnt);
        }
        printf("%d\n",minc);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: