• hdu 1394 求一个序列的最小逆序数 单点增 区间求和


    题目的意思就好比给出一个序列

    如:0 3 4 1 2

    设逆序数初始n = 0;

    由于0后面没有比它小的,n = 0

    3后面有1,2 n = 2

    4后面有1,2,n = 2+2 = 4;

    所以该序列逆序数为 4

    或者这样想

    先输0 前面没有比它大的 n = 0
    3也没有 4也没有
    1前面 3 4 比它大 n += 2
    2前面 3 4 比它大 n += 2
    n = 4

    其根据题意移动产生的序列有

    3 4 1 2 0 逆序数:8

    4 1 2 0 3 逆序数:6

    1 2 0 3 4 逆序数:2

    2 0 3 4 1 逆序数:4

    所以最小逆序数为2

    Sample Input
    10
    1 3 6 9 0 8 5 7 4 2

    Sample Output
    16

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <cstring>
     4 # include <algorithm>
     5 # include <cmath>
     6 # include <queue>
     7 # define LL long long
     8 using namespace std ;
     9 
    10 const int maxn = 5010;
    11 
    12 int sum[maxn<<2] ; //结点开4倍
    13 int x[maxn] ;
    14 
    15 void PushUP(int rt) //更新到父节点
    16 {
    17     sum[rt] = sum[rt * 2] + sum[rt * 2 + 1] ; //rt 为当前结点
    18 }
    19 
    20 void build(int l , int r , int rt) //构建线段树   所有点都置零
    21 {
    22     sum[rt] = 0 ;
    23     if (l == r)
    24     {
    25         return ;
    26     }
    27     int m = (l + r) / 2 ;
    28     build(l , m , rt * 2) ;
    29     build(m + 1 , r , rt * 2 +1) ;
    30 
    31 }
    32 
    33 void updata(int p  , int l , int r , int rt)  //单点增
    34 {
    35     if (l == r)
    36     {
    37         sum[rt]++ ;
    38         return ;
    39     }
    40     int m = (l + r) / 2 ;
    41     if (p <= m)
    42        updata(p , l , m , rt * 2) ;
    43     else
    44        updata(p  , m + 1 , r , rt * 2 + 1) ;
    45     PushUP(rt) ;
    46 }
    47 
    48 int query(int L , int R , int l , int r , int rt)  //区间求和
    49 {
    50     if (L <= l && r <= R)
    51         return sum[rt] ;
    52     int m = (l + r) / 2 ;
    53     int ret = 0 ;
    54     if (L <= m)
    55        ret += query(L , R , l , m , rt * 2) ;
    56     if (R > m)
    57        ret += query(L , R , m + 1 , r , rt * 2 + 1) ;
    58     return ret ;
    59 }
    60 
    61 int main ()
    62 {
    63     //freopen("in.txt","r",stdin) ;
    64     int n ;
    65     while(scanf("%d" , &n) != EOF)
    66     {
    67         build(0 , n - 1 , 1) ; //因为序列里有0 所以要从0开始
    68         int sum = 0 ;
    69         int i ;
    70         for (i = 0 ; i < n ; i++)
    71         {
    72            scanf("%d" , &x[i]) ;
    73            sum += query(x[i] , n-1 , 0 , n-1 , 1) ;  //sum累加的是 现在输入的x[i] 和 之前输入的数相比 有几个比它大  也就是逆序
    74            updata(x[i] , 0 , n-1 , 1) ;
    75         }
    76            int ret = sum ;  //当前输入序列的逆序
    77         for (i = 0 ; i < n ; i++)   //每次循环 都是将之前的序列的第一位以移到最后一位
    78         {
    79            sum += n - x[i] - x[i] - 1 ;  //sum为移动后的逆序
    80            ret = min(ret , sum) ;
    81         }
    82         printf("%d
    " , ret) ;
    83     }
    84 
    85     return 0 ;
    86 }
    View Code
  • 相关阅读:
    Oracle 日期总结
    JavaScript 获取文件名,后缀名
    JavaScript Array pop(),shift()函数
    JavaScript Array splice函数
    Oracle 创建表空间、临时表空间、创建用户并指定表空间、授权,删除用户及表空间
    eclipse debug调试java程序的九个技巧
    Oracle dos连接数据库基本操作
    Oracle 隐式游标 存储过程
    Oracle 修改表名
    Oracle 时间 MM-dd形式转换
  • 原文地址:https://www.cnblogs.com/mengchunchen/p/4603211.html
Copyright © 2020-2023  润新知