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;
    }
  • 相关阅读:
    MySQL Explain优化
    mysql联合索引
    MySQL索引类型
    php常用的排序算法与二分法查找
    mysql 主从复制(mysql双机热备的实现)
    mysql 主从复制 (2)
    Linux 查看进程之PS命令
    PHP isset 和 array_key_exists 对比
    Linux md5sum 的用法
    Linux Sphinx 安装与使用
  • 原文地址:https://www.cnblogs.com/pach/p/7348938.html
Copyright © 2011-2022 走看看