title: 线段树-最小逆序数

date: 2018-10-12 17:19:16

tags:

  • acm
  • 算法
  • 刷题

    categories:
  • ACM-线段树

概述

这是一道简单的线段树的题,,,当然还有很多其他的做法,,,甚至时暴力都可以,,,

用线段树主要是为了在练一练线段树的使用,,,而且这次,,我换了一种写线段树的方法,,,

貌似也是很多大佬都在用的一种写法,,,

之前一直用的入门时为了好理解的一种写法:节点用结构体node表示,,,并且为了理解还添了每一个节点所对应的左右边界,,,

但实际上,,这些信息是没有用的,,,或者说是多余的,,,直接在使用时计算或者直接作为函数的形参传递就行了,,,,

这样的写法代码量更加的少而写写起来也方便,,,占用的空间也少了些,,,

题目的分析

这道题不像之前做的线段树的题那样所维护的值就是最终要求的答案,,,而是中间的某一过程量,,,

首先,,题目的意思就是对于一个给定的数列 \(a_0 , a_1 , a_2 , ,,, ,a_{n-1}\),,,每次将第一个数移动到后面,,,这样一共有n种序列,,,然后对于每一种序列都有一个 逆序数 ,,问你在这些逆序数中最小的那个是多小,,,,

  • 这道题只要知道其中一个序列的逆序数,,它的相邻一个逆序数也就可以推出来,,,具体是这样的:

    \(当已知第i个序列的逆序数sum_i时,,\)

    \(第i+1个序列的逆序数为sum_{i+1}=sum_i + n - a[i] - 1 - a[i],,,,\)

    \(就是说当将第一个数移到最后前,,,\)

    \(它以前的逆序数有 a[i] 个所以要减去这些,,\)

    \(而当它被移到最后时,,,\)

    \(前面又多了 n - a[i] - 1 个,,,\)

    \(最后的sum就求出来了,,,\)

  • 当知道上面这个递推式后,,,我们的任务就是求出所输入出的数列的逆序数,,,然后再根据递推式找出最小的那一个输出就行了,,,

  • 对于求这个数列的逆序数用线段树的方法是,,,先建一个空的数,,,然后每输入一个数,,标记一下,,不过标记在最后的更新完成,,,先求出它之前所输入的所有数中比它大的数(也就是看这个数到n-1一共有几个出现在之前的输入中,,,也就是看标记的和),,,也就是以它构成的逆序列,,,然后把它加(标记)到这个树里(更新),,,可以看出如果把标记改为存放这个数,,纳闷这棵树的叶子节点就是排序好的1~n-1数列,,,,这一段画个图就好理解了,,,

实现

code:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. using namespace std;
  5. #define lson rt<<1,l,mid
  6. #define rson rt<<1|1,mid+1,r
  7. const int maxn = 5005;
  8. int sum[maxn << 2];
  9. void pushup(int rt)
  10. {
  11. sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
  12. }
  13. void build(int rt , int l , int r)
  14. {
  15. sum[rt] = 0;
  16. if(l == r)
  17. return;
  18. int mid = (l + r) >> 1;
  19. build(lson);
  20. build(rson);
  21. pushup(rt);
  22. }
  23. void update(int rt , int l , int r , int loc)
  24. {
  25. if(l == r)
  26. {
  27. ++sum[rt];
  28. return;
  29. }
  30. int mid = (l + r) >> 1;
  31. if(loc <= mid) update(lson , loc);
  32. else update(rson , loc);
  33. pushup(rt);
  34. }
  35. int query(int rt , int l , int r , int L , int R)
  36. {
  37. if(L <= l && r <= R)
  38. return sum[rt];
  39. int mid = (l + r) >> 1;
  40. int ans = 0;
  41. if(L <= mid) ans += query(lson , L , R);
  42. if(R > mid) ans += query(rson , L , R);
  43. return ans;
  44. }
  45. int a[maxn];
  46. int main()
  47. {
  48. int n;
  49. while(scanf("%d" , &n) != EOF)
  50. {
  51. build(1 , 0 , n);
  52. int sm = 0;
  53. for(int i = 0; i < n; ++i)
  54. {
  55. scanf("%d" , &a[i]);
  56. sm += query(1 , 0 , n - 1 , a[i] , n - 1);
  57. update(1 , 0 , n - 1 , a[i]);
  58. }
  59. int ret = sm;
  60. for(int i = 0; i < n; ++i)
  61. {
  62. sm += n - a[i] - 1 - a[i];
  63. ret = min(sm , ret);
  64. }
  65. printf("%d\n" , ret);
  66. }
  67. }

线段树-最小逆序数hdu1394的更多相关文章

  1. hdu 1394(线段树) 最小逆序数

    http://acm.hdu.edu.cn/showproblem.php?pid=1394 给出一列数组,数组里的数都是从0到n-1的,在依次把第一个数放到最后一位的过程中求最小的逆序数 线段树的应 ...

  2. HDU_1394_Minimum Inversion Number_线段树求逆序数

    Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java ...

  3. hdu 1394 线段树计算逆序数

    线段树计算逆序数的原理: 用线段树来统计已插入的数的个数(所以要保证最大的那个数不能太大,否则数组都开不了),然后每插入一个数,就查询比插入的数大的个数,累加即可. 这个题还有一个特点就是,题目给的是 ...

  4. 【线段树求逆序数】【HDU1394】Minimum Inversion Number

    题目大意: 随机给你全排列中的一个,但不断的把第一个数丢到最后去,重复N次,形成了N个排列,问你这N个排列中逆序数最小为多少 做法: 逆序数裸的是N^2 利用线段树可以降到NlogN 具体方法是插入一 ...

  5. 线段树求逆序数方法 HDU1394&amp;&amp;POJ2299

    为什么线段树能够求逆序数? 给一个简单的序列 9 5 3 他的逆序数是3 首先要求一个逆序数有两种方式:能够从头開始往后找比当前元素小的值,也能够从后往前找比当前元素大的值,有几个逆序数就是几. 线段 ...

  6. hdu1394 Minimum Inversion Number (线段树求逆序数&&思维)

    题目传送门 Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

  7. HDU-1394 Minimum Inversion Number(线段树求逆序数)

    Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Ot ...

  8. HDU - 1394 Minimum Inversion Number (线段树求逆序数)

    Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs ( ...

  9. hdu 1394 (线段树求逆序数)

    <题目链接> 题意描述: 给你一个有0--n-1数字组成的序列,然后进行这样的操作,每次将最前面一个元素放到最后面去会得到一个序列,那么这样就形成了n个序列,那么每个序列都有一个逆序数,找 ...

随机推荐

  1. 如何写一个好bug

      自己的总结,和大家分享~

  2. [转载]WCF和ASP.NET Web API在应用上的选择

    http://www.cnblogs.com/shanyou/archive/2012/09/26/2704814.html http://msdn.microsoft.com/en-us/libra ...

  3. Visual Leak Detector原理剖析

    认识VLD VLD(Visual Leak Detector)是一款用于Visual C++的开源内存泄漏检测工具,我们只需要在被检测内存泄漏的工程代码里#include “vld.h”就可以开启内存 ...

  4. 【Linux 命令】 rsync 目录覆盖软链接,保持软链接不变并同步目录内容

    需求:有两个相同文件名的目录需要使用其中一个目录覆盖另外一个  问题: 被覆盖目录下存在软链接,但在源目录下软链接是一个目录 需要解决的方案: 要求将原目录里和被覆盖目录里冲突的目录文件复制到B的软链 ...

  5. R的农场 chebnear

    评测传送门 Description最近,R 终于获得了一片他梦寐以求的农场,但如此大的一片农场,想要做好防卫工作可不是一件容易的事.所以 R 购买了 N 个守卫,分别让他们站在一定的位置上(守卫不可移 ...

  6. zzd 的割草机(Lawnmower)

    评测传送门 [题目描述] 已知花坛为一个 n * m 的矩形,草只会长在某些个格子上,zzd 有一个割草机,一开始,zzd 站在(1,1)处,面向(1,m)(面向右).每次 zzd 有两个选择(耗费一 ...

  7. linux环境下mysql默认是区分表名大小写的

    在linux环境下,mysql默认表明是区分大小写的,我们可以查看全局变量发现: mysql> show variables like 'lower%'; +------------------ ...

  8. 【Java基础】JAVA不可变类(immutable)机制与String的不可变性

    一.不可变类简介 不可变类:所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值.如JDK内部自带的很多不可变类:Interger.Long和String(8种基本数据类型的包装类和S ...

  9. 4 - django-orm基本使用

    目录 1 数据库与ORM 2 orm的配置 2.1 引擎和配置 2.2 mysql驱动程序 3 orm 表模型 3.1 创建表对象 3.2 Django字段类型 3.3 常用字段参数说明 3.4 特殊 ...

  10. Ubuntu下安装arm-linux-gnueabi-xxx编译器【转】

    转自:http://blog.csdn.net/real_myth/article/details/51481639 from: http://www.linuxdiyf.com/linux/1948 ...