题意 : 给出一个数n(n<500,000), 再给出n个数的序列 a1、a2.....an每一个ai的范围是 0~999,999,999  要求出当通过相邻两项交换的方法进行升序排序时需要交换的次数

分析:其实经过一次模拟后,会发现奇妙的东西,这个排序都是按位置排的,最大要求到最大,最小要去到最小,转化思想这是一道求逆序对数的题目,答案就是逆序对数。

这里数据过大999999999,数组无法开的了这么大,我们可以离散化,只记录相对大小。

这里离散化有所不同,这里为了压时,用了空间换时间的方法. 前面的文章有讲到sum(i)表示前面有多少比这个小的数,可以sum(n)-sum(i), 这里有新知识就是sum(i)表示有多少小的数,那当前的总数是i,那大的数就是(i-sum(i)这也是求逆序对的方法,目测挺快的。

  1. .解释为什么要有离散的这么一个过程?
  2. 刚开始以为999..999这么一个数字,对于int存储类型来说是足够了。
  3. 还有只有500000个数字,何必要离散化呢?
  4. 刚开始一直想不通,后来明白了,后面在运用树状数组操作的时候,
  5. 用到的树状数组C[i]是建立在一个有点像位存储的数组的基础之上的,
  6. 不是单纯的建立在输入数组之上。
  7. 比如输入一个9 ,那么C[i]树状数组的建立是在,
  8.  
  9. 数据: p[i].val
  10. 编号: p[i].oder = i*************
  11. sort
  12. 数据:
  13. 编号:
  14. 顺序:
  15.  
  16. a[p[i].编号] = 顺序号;**********************
  17.  
  18. a[] = <--;
  19. a[] = <--;
  20. a[] = <--;
  21. a[] = <--;
  22. a[] = <--;
  23.  
  24. a[]={ }
  25.  
  26. 新号:
  27.  
  28. 下标
  29. 数组
  30. 现在由于999999999这个数字相对于500000这个数字来说是很大的,
  31. 所以如果用数组位存储的话,那么需要999999999的空间来存储输入的数据。
  32. 这样是很浪费空间的,题目也是不允许的,所以这里想通过离散化操作,
  33. 使得离散化的结果可以更加的密集。
  34. 简言之就是开一个大小为这些数的最大值的树状数组
  35. . 怎么对这个输入的数组进行离散操作?
  36. 离散化是一种常用的技巧,有时数据范围太大,可以用来放缩到我们能处理的范围;
  37. 因为其中需排序的数的范围0--- ;显然数组不肯能这么大;
  38. N的最大范围是500 ;故给出的数一定可以与1.。。。N建立一个一一映射;
  39. ()当然用map可以建立,效率可能低点;
  40. ()这里用一个结构体
  41. struct Node
  42. {
  43. int val,pos;
  44. }p[];和一个数组a[];
  45.  
  46. 其中val就是原输入的值,pos是下标;
  47. 然后对结构体按val从小到大排序;
  48.  
  49. 此时,val和结构体的下标就是一个一一对应关系,
  50. 而且满足原来的大小关系;
  51.  
  52. for(i=;i<=N;i++)
  53. a[p[i].pos]=i;
  54.  
  55. 然后a数组就存储了原来所有的大小信息;
  56. 比如 ------- 离散后aa数组
  57. 就是
  58. 具体的过程可以自己用笔写写就好了。
  59.  
  60. . 离散之后,怎么使用离散后的结果数组来进行树状数组操作,计算出逆序数?
  61. 如果数据不是很大, 可以一个个插入到树状数组中,
  62. 每插入一个数, 统计比他小的数的个数,
  63. 对应的逆序为 i- sum( a[i] ),
  64. 其中 i 为当前已经插入的数的个数,
  65. sum( a[i] )为比 a[i] 小的数的个数,
  66. i- sum( a[i] ) 即比 a[i] 大的个数, 即逆序的个数
  67. 但如果数据比较大,就必须采用离散化方法
  68. 假设输入的数组是9 离散后的结果a[] = {,,,,};
  69. 在离散结果中间结果的基础上,那么其计算逆序数的过程是这么一个过程。
  70. .输入5 调用add(, ),把第5位设置为1
  71.  
  72. 计算1-5上比5小的数字存在么? 这里用到了树状数组的sum() = 1操作,
  73. 现在用输入的下标1 -sum() = 就可以得到对于5的逆序数为0
  74. . 输入2 调用add(, ),把第2位设置为1
  75.  
  76. 计算1-2上比2小的数字存在么? 这里用到了树状数组的sum() = 1操作,
  77. 现在用输入的下标2 - sum() = 就可以得到对于2的逆序数为1
  78. . 输入1 调用add(, ),把第1位设置为1
  79.  
  80. 计算1-1上比1小的数字存在么? 这里用到了树状数组的sum() = 1操作,
  81. 现在用输入的下标 -sum() = 就可以得到对于1的逆序数为2
  82. . 输入4 调用add(, ),把第5位设置为1
  83.  
  84. 计算1-4上比4小的数字存在么? 这里用到了树状数组的sum() = 3操作,
  85. 现在用输入的下标4 - sum() = 就可以得到对于4的逆序数为1
  86. . 输入3 调用add(, ),把第3位设置为1
  87.  
  88. 计算1-3上比3小的数字存在么? 这里用到了树状数组的sum() = 3操作,
  89. 现在用输入的下标5 - sum() = 就可以得到对于3的逆序数为2
  90. . ++++ = 这就是最后的逆序数
  91. 分析一下时间复杂度,首先用到快速排序,时间复杂度为O(NlogN),
  92. 后面是循环插入每一个数字,每次插入一个数字,分别调用一次add()和sum()
  93. 外循环N, add()和sum()时间O(logN) => 时间复杂度还是O(NlogN)
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <algorithm>
  4. using namespace std;
  5. typedef long long ll;
  6. const int N=5e5+;
  7.  
  8. struct node{
  9. int val;
  10. int pos;
  11. }p[N];
  12.  
  13. int n,bit[N],a[N];
  14.  
  15. bool cmp(const node&a, const node& b){
  16. return a.val<b.val;
  17. }
  18.  
  19. void add(int i){
  20. while(i<=n){
  21. bit[i]+=;
  22. i+=i&-i;
  23. }
  24. }
  25.  
  26. int sum(int i){
  27. int s=;
  28. while(i>){
  29. s+=bit[i];
  30. i-=i&-i;
  31. }
  32. return s;
  33. }
  34.  
  35. void solve(){
  36. for(int i=; i<=n; i++){
  37. scanf("%d",&p[i].val);
  38. p[i].pos=i;
  39. }
  40. sort(p+,p+n+,cmp);//排序
  41. for(int i=; i<=n; i++)a[p[i].pos]=i;//离散化
  42. ll ans=;
  43. for (int i=; i<=n; i++) bit[i]=; //初始化树状数组
  44. for(int i=; i<=n; i++){
  45. add(a[i]);
  46. ans+=i-sum(a[i]);
  47. }
  48. printf("%I64d\n",ans);
  49. }
  50.  
  51. int main(){
  52. while(~scanf("%d",&n)&&n){
  53. solve();
  54. }
  55. return ;
  56. }

POJ 2299 Ultra-QuickSort (树状数组 && 离散化&&逆序)的更多相关文章

  1. poj 2299 Ultra-QuickSort(树状数组求逆序数+离散化)

    题目链接:http://poj.org/problem?id=2299 Description In this problem, you have to analyze a particular so ...

  2. poj 2299 Ultra-QuickSort(树状数组求逆序数)

    链接:http://poj.org/problem?id=2299 题意:给出n个数,求将这n个数从小到大排序,求使用快排的需要交换的次数. 分析:由快排的性质很容易发现,只需要求每个数的逆序数累加起 ...

  3. POJ 2299 Ultra-QuickSort(树状数组+离散化)

    http://poj.org/problem?id=2299 题意:给出一组数,求逆序对. 思路: 这道题可以用树状数组解决,但是在此之前,需要对数据进行一下预处理. 这道题目的数据可以大到999,9 ...

  4. POJ - 2299 Ultra-QuickSort 【树状数组+离散化】

    题目链接 http://poj.org/problem?id=2299 题意 给出一个序列 求出 这个序列要排成有序序列 至少要经过多少次交换 思路 求逆序对的过程 但是因为数据范围比较大 到 999 ...

  5. POJ 2299 Ultra-QuickSort【树状数组 ,逆序数】

    题意:给出一组数,然后求它的逆序数 先把这组数离散化,大概就是编上号的意思--- 然后利用树状数组求出每个数前面有多少个数比它小,再通过这个数的位置,就可以求出前面有多少个数比它大了 这一篇讲得很详细 ...

  6. Ultra-QuickSort(树状数组求逆序对数)

    Ultra-QuickSort 题目链接:http://poj.org/problem?id=2299 Time Limit: 7000MS   Memory Limit: 65536K Total ...

  7. hdu2838树状数组解逆序

    离散化和排序后的序号问题搞得我实在是头痛 不过树状数组解逆序和偏序一类问题真的好用 更新:hdu的数据弱的真实,我交上去错的代价也对了.. 下面的代码是错的 /* 每个点的贡献度=权值*在这个点之前的 ...

  8. [zoj4046][树状数组求逆序(强化版)]

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4046 题意:有一个含有n个元素的数列p,每个元素均不同且为1~n中的一个, ...

  9. poj 2299 Ultra-QuickSort(树状数组)

    Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 67681   Accepted: 25345 ...

随机推荐

  1. java判断姓是否合格 百家姓

    package util; import java.lang.reflect.Array; public class FirstName { public static boolean ClearNa ...

  2. Android开源地图项目 BigPlanetTracks 学习随笔

    一.         app主体部分 [tyt.android.bigplanettracks] 二.         地图部分 [tyt.android.bigplanettracks.maps] ...

  3. JavaScript中常用的函数

    javascript函数一共可分为五类:  ·常规函数  ·数组函数  ·日期函数  ·数学函数  ·字符串函数 1.常规函数  javascript常规函数包括以下9个函数:  (1)alert函数 ...

  4. clearfix的用法(转)

    clearfix的用法 (2013-12-31 10:41:24) 标签: clearfix 清除浮动 clearboth height zoom 分类: 网页制作 如果有一个DIV作为外部容器,内部 ...

  5. 百度Apollo解析——2.log系统

    Apollo中的glog 在Apollo中google glog 被广泛使用,glog 是 google 的一个 c++ 开源日志系统,轻巧灵活,入门简单,而且功能也比较完善. 1. 安装 以下是官方 ...

  6. SpringBoot06 统一响应格式

    1 要求 每个请求成功后,后台返回的响应格式都是一致的,例如: 2 创建一个视图模型 该模型用于格式化响应数据 package cn.xiangxu.springboottest.model.data ...

  7. hihocoder1513 小Hi的烦恼

    传送门 分析 论bitset的妙用......我们利用桶排将输入的数据排序,之后分别考虑5维,a[i][j]表示考虑第i个人第j维的情况下于其它人的大小关系.最后将5维的信息并起来求1的个数即可 代码 ...

  8. 914D Bash and a Tough Math Puzzle

    传送门 分析 用线段树维护区间gcd,每次查询找到第一个不是x倍数的点,如果这之后还有gcd不能被x整除的区间则这个区间不合法 代码 #include<iostream> #include ...

  9. HTML完全使用详解 PDF扫描版​

    <HTML完全使用详解>根据网页制作的实际特点和目前市场需要,全面系统地介绍了最新的HTML4.01.丰富的实例贯穿全书,能帮助您全面掌握HTML,而且本书所有实例均可直接修改使用,可以提 ...

  10. 无废话MVC入门教程笔记

    自学mvc,看了园子里李林峰写的李林峰写的无废话MVC入门教程笔记,现在有的平时忽略的或是不太清楚的点记下来 1,Html.DropDownList //服务端写法 @{ //下拉列表的值 List& ...