hdu 1394 Minimum Inversion Number (数据结构_线段树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394


题目大意:给定一个序列,求逆序数总和,也就是在当前位置后面比当前值小的数的个数。这题的序列,前后可以滑动即第一个可能变到最后面。


解题思路:换个角度找逆序数,即在当前位置之前比当前值大的数的个数,那只要在每次输入一个数的时候寻找x+1...n-1里出现过的个数。那关键问题就是如果快速地查找到逆序数,如果暴力,n^2,也可以过。但考虑用线段树查询,其实就是很普通的线段树。关于线段树,可以去傻崽的空间膜拜下www.notonlysuccess.com.然后找最小的逆序数总和,则可以一个个往后挪,tot = tot + (n - arr[i]) - (arr[i] - 1),ans = min(tot).


测试数据:

5

 5 4 3 2 1

6

1 0 2 3 4 5


代码:

#include <stdio.h>
#include <string.h>
#define MAX 6000
#define lson l,m,rt << 1
#define rson m+1,r,rt << 1 | 1
#define min(a,b) (a) < (b) ? (a) : (b)
#define max(a,b) (a) > (b) ? (a) : (b)


int sum[MAX*4],n;
int tot,arr[MAX],cnt;


void PushUp(int rt) {

    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
int query(int L,int R,int l,int r,int rt) {

    if (L <= l && r <= R) {

        return sum[rt];
    }


    int m = (l + r) >> 1,ret = 0;
    if (L <= m) ret += query(L,R,lson);
    if (R > m) ret += query(L,R,rson);
    return ret;
}
void update(int p,int l,int r,int rt) {

    if (l == r)  {
        
        sum[rt]++;
        return ;
    }


    int m = (l + r) >> 1;
    if (p <= m) update(p,lson);
    else update(p,rson);
    PushUp(rt);
}


int main() {

    int i,j,k,t;


    while (scanf("%d",&n) != EOF) {

        tot = 0;
        for (i = 0; i <= 4 * n + 1; ++i)
            sum[i] = 0;
        for (i = 0; i < n; ++i) {

            scanf("%d",&arr[i]);
            tot += query(arr[i],n-1,0,n-1,1);
            update(arr[i],0,n-1,1);
        }
        

        int ret = tot;
        for (i = 0; i < n; ++i) {

            tot += n - arr[i]  - 1 - arr[i];
            ret = min(tot,ret);
        }
        printf("%d\n",ret);
    }
}


本文ZeroClock原创,但可以转载,因为我们是兄弟。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值