zoukankan      html  css  js  c++  java
  • hdu 1394 线段树计算逆序数

    线段树计算逆序数的原理:

    用线段树来统计已插入的数的个数(所以要保证最大的那个数不能太大,否则数组都开不了),然后每插入一个数,就查询比插入的数大的个数,累加即可。

    这个题还有一个特点就是,题目给的是0至n-1的全排列,也就是说每个数都不同。那么abcde的逆序数与bcdea的逆序数就很明了了。

    假设比a小的数有t个,那么比a大的数有n-t-1个,那么abcde转换至bcdea的逆序数就增加了n-t-1,减少了t

    不需要build函数建树,因为初始状态没有数插入,直接menset就可以了

    #include <bits/stdc++.h>
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1|1
    using namespace std;
    
    const int MAXN = 5008;
    int cnt[MAXN<<2];
    
    int query(int L, int R, int l, int r, int rt)
    {
        if(L <= l && r <= R) return cnt[rt];
        int ret = 0;
        int m = (l + r) >> 1;
        if(L <= m) ret += query(L, R, lson);
        if(R > m) ret += query(L, R, rson);
        return ret;
    }
    
    void updata(int p, int l, int r, int rt)
    {
        if(l == r)
        {
            cnt[rt]++;
            return;
        }
        int m = (l + r) >> 1;
        if(p <= m) updata(p, lson);
        else updata(p, rson);
        cnt[rt] = cnt[rt<<1] + cnt[rt<<1|1];
    }
    
    int a[MAXN];
    
    int main()
    {
    //    freopen("in.txt", "r", stdin);
        int n;
        while(~scanf("%d", &n))
        {
            memset(cnt, 0, sizeof(cnt));
            int sum = 0;
            for(int i=0; i<n; i++)
            {
                scanf("%d", &a[i]);
                sum += query(a[i]+1, n-1, 1, n, 1);
                updata(a[i], 1, n, 1);
            }
            int ans = sum;
            for(int i=0; i<n; i++)
            {
                sum += n - 2*a[i] - 1;
                ans = min(ans, sum);
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    OA系统权限管理设计方案【转】
    UML类图几种关系的总结
    在pl/sql中使用exp/imp工具实现oracle数据导出/导入
    page 的范围
    JSP页面跳转的五种方法
    Start with...Connect By
    秒杀系统架构
    对系统负载的理解
    sort(7)
    cat(6)
  • 原文地址:https://www.cnblogs.com/pach/p/7348938.html
Copyright © 2011-2022 走看看