• HDU 1394 Minimum Inversion Number 线段树


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

      题目大意:给出一个n排列, 进行n中变换, 求最大逆序数

      解题思路: 已知一个数列的逆序数, 那么他的变换可以O(1)求出来, 所以现在的主要问题就是求一组排列的逆序数, n 小于等于5000, 完全可以暴力, 但是现在用线段树做。由于是一组n排列, 而且我们只关心一个数前面的比他大的数, 那当我们插入a[i]时, 只需要查询0 ~ i-1 中 a[i] ~ n-1 内的数的个数就可以了, 我们可以先造一颗0的空树, 这样我们查询的时候就就直接查全部序列就可以。sum数组一开始是0, 由于一个数字只出现一次, 所以只要统计sum[a[i]]  ~ sum[n-1] 之和就可以了, 注意更新函数update(int p, int l, int r, int rt ) 改成了if(l==r) sum[p]++;

      代码: 

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <map>
    #include <cstring>
    #include <iterator>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <deque>
    #include <map>
    
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1|1
    
    const int maxn = 5000+7;
    using namespace std;
    int sum[4*maxn];
    int arr[maxn];
    
    void Pushplus( int rt ) {
        sum[rt] = sum[rt<<1] + sum[rt<<1|1];
        return;
    }
    
    void build( int l, int r, int rt ) {
        sum[rt] = 0;
        if( l == r ) return;
        int m = (l + r) >> 1;
        build( lson );
        build( rson );
        return;
    }
    
    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;
        int 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);
        Pushplus(rt);
    }
    
    int main() {
        int n;
        while( scanf( "%d", &n ) == 1 ) {
            build( 0, n-1, 1 );
            int sum = 0;
            for( int i = 0; i < n; i++ ) {
                scanf( "%d", arr + i );
                sum += Query( arr[i], n-1, 0, n-1, 1 );
                update(arr[i], 0, n-1, 1);
            }
            int ret = sum;
            for( int i = 0; i < n; i++ ) {
                sum += n - arr[i] - arr[i] - 1;
                ret = min( ret, sum );
            }
            printf( "%d
    ", ret );
        }
    }
    View Code

      思考: 刚才在车上才想通了这个问题, 果然做树的题就是需要理清自己的思路, 现在好热......今天看了最基础的线段树, 以后着重线段树和dp, 今天晚上来一道DP题, 当然是在游泳完之后啦,哈哈哈哈哈!

  • 相关阅读:
    .net AJAX运行错误 未能加载文件或程序集 "System.Web....”的解决办法
    mysql免安装版使用方法
    XP下IIS+php 5.2.4配置
    distinct order by
    手机操作系统介绍
    .net自带 SQL Server 2005 Express使用
    统计字符串数组中每个字符串所出现的次数
    juqery 学习之三 选择器<层级><基本>
    juqery 学习之三 选择器<简单><内容>
    juqery 学习之三 选择器<可见性><元素属性>
  • 原文地址:https://www.cnblogs.com/FriskyPuppy/p/7286071.html
Copyright © 2020-2023  润新知