以前都学过树状数组,但是已经差不多忘记了!不过看一看后,马上就都回忆起来了!而且感觉经过这么久的学习,对树状数组有了更深一层的领悟!个人觉得树状数组在本质上与线段树是没有区别的!都是管理区间,只不过树状数组管理区间的方式不一样罢了!

经过了解后就学习着解决hdu1754那道水题吧!我在网上看到的代码多半是用线段树解决的!这里把用色树状数组的解决代码贴出来吧!

7097586 2012-11-06 16:32:30 Accepted 1754 593MS 2620K 1524 B C++ xiaoshuai
  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<algorithm>
  4. #define M 200005
  5. using namespace std;
  6. int a[M];
  7. int Max[M];
  8. int hash[M];
  9. int n,m;
  10. int lowbit(int x){
  11. return x&(-x);
  12. }
  13. void build(int pos,int val){
  14. while(pos<=n){
  15. if(hash[pos]==0){
  16. Max[pos]=val;
  17. hash[pos]++;
  18. }else{
  19. Max[pos]=max(Max[pos],val);
  20. }
  21. pos+=lowbit(pos);
  22. }
  23. }
  24. void update(int pos,int val){
  25. //修改这元素 影响到的空间的值
  26. int i,j,k;
  27. a[pos]=val;//修改原始数组的值
  28. for(i=pos;i<=n;i+=lowbit(i)){
  29. Max[i]=a[i];
  30. if(lowbit(i)>1){
  31. for(j=i-1,k=i-lowbit(i)+1;j>=k;j-=lowbit(j)){
  32. Max[i]=max(Max[i],Max[j]);
  33. }
  34. }
  35. }
  36. }
  37. int query(int ll,int rr){
  38. int ans=a[rr];
  39. while(true){
  40. ans=max(ans,a[rr]);
  41. if(ll==rr)break;
  42. for(rr-=1;rr-ll>=lowbit(rr);rr-=lowbit(rr)){
  43. ans=max(ans,Max[rr]);
  44. }
  45. }
  46. return ans;
  47. }
  48. int main(){
  49. int i;
  50. char s[2];
  51. int ll,rr;
  52. int ans;
  53. while(scanf("%d %d",&n,&m)!=EOF){
  54. memset(hash,0,sizeof(hash));
  55. for(i=1;i<=n;i++){
  56. scanf("%d",&a[i]);
  57. build(i,a[i]);
  58. }
  59. for(i=0;i<m;i++){
  60. scanf("%s %d %d",s,&ll,&rr);
  61. if(s[0]=='U'){
  62. update(ll,rr);
  63. }else{
  64. ans=query(ll,rr);
  65. printf("%d\n",ans);
  66. }
  67. }
  68. }
  69. return 0;
  70. }

尽管这道题是如此简单,但是依然花了我大半天的时间!看来自己的代码能力还是需要提高啊!查询的方法是借鉴了(博客现在找不到了)!把原始数据加进去操作和更新的操作是我自己写的! 说实话,看懂与自己拍出来的差距真的挺大的!

特别是加入数据的操作,最开始学习树状数组是用电子科大的PPT里面的例子!

就是区间求和:

  1. #include<stdio.h>
  2. #include<string.h>
  3. int n=5;
  4. int a[6]={0,1,2,3,4,5};
  5. int sum[6];
  6. int lowbit(int t){
  7. return t&-t;
  8. }
  9. void update(int pos,int val){
  10. while(pos<=n){
  11. sum[pos]+=val;
  12. pos+=lowbit(pos);
  13. }
  14. }
  15. int query(int pos){
  16. int ans=0;
  17. while(pos>0){
  18. ans+=sum[pos];
  19. pos-=lowbit(pos);
  20. }
  21. return ans;
  22. }
  23. int main(){
  24. memset(sum,0,sizeof(sum));
  25. for(int i=1;i<=n;i++){
  26. update(i,a[i]);
  27. }
  28. int ans=query(5);
  29. printf("ans=%d\n",ans);
  30. return 0;
  31. }

当时我的思路也仅限于 用数状数组来求和! 学习线段树的时候,求和与求最大值几乎是没有区别的!但是用树状数组我就一下子转不过来了!转不过来的时候,一定要弄清楚的是sum数组中存储的到底是什么?sum[i]表示i管理的区间之和!i管理的区间是哪一段呢?[i-lowbit(i}+1,i] 这个区间自己画一画就出来了!

好了,回到就最值的问题!这里我为什么会用到hash呢?主要是对Max数组的初始化问题,我想如果有负数出现,而把Max数组初始化为0或者-1肯定是不对的!怎么办呢?用hash吧!只要位置i是第一次访问,Max[i]肯定与val是相等的!这样就解决了初始化数据的问题!

真正卡了我好久的地方是update(int pos,int val),就是如果要修改一个值,我们怎么办?

这里就一定要理解清楚树状数组是怎么管理区间的!因为把pos位置的value修改后,Max数组可能是需要改变的!改变什么呢?修改pos位置影响到的区间!比如:pos=8,则Max[8],Max[16]的值都可能发生变化!我当时就是在修改区间的位置一直纠缠着!Max[8]=max(a[8],Max[7],Max[6],Max[4])!  那么怎么按顺序遍历8,7,6,4呢?用到lowbit()!

经过一次又一次的wrong answer,一次又一次的反思,最终得到的update代码如下:

  1. void update(int pos,int val){
  2. int i,j,k;
  3. a[pos]=val;//修改原始数组的值
  4. for(i=pos;i<=n;i+=lowbit(i)){ //修改这元素 影响到的空间的值
  5. Max[i]=a[i];//由于a[i]的值已经变化,所以Max[i]的值可能不再是原来的值,需要我们重新求
  6. if(lowbit(i)>1){//这里k=i-lowbit(i)+1,表示下标i管理的区间的起点即i下标管理区间[k,i]
  7. for(j=i-1,k=i-lowbit(i)+1;j>=k;j-=lowbit(j)){
  8. Max[i]=max(Max[i],Max[j]);
  9. }
  10. }
  11. }
  12. }

学习算法是一个悟的过程!所谓“觉悟”,觉是一个瞬间,悟是一个过程。把所有的觉的瞬间,与长长一生的悟结合起来,你所到达的就是终于看见我的心。这是人生的的觉悟。

慢慢接着悟吧!

用树状数组解决求区间最值的问题:hdu1754相关推荐

  1. SPOJ D-query 树状数组离线 求区间内不同数字的个数

    Given a sequence of n numbers a1, a2, -, an and a number of d-queries. A d-query is a pair (i, j) (1 ...

  2. 树状数组(求子区间和+更新元素值)

    树状数组 欲完成修改值和查询区间和两种操作 求前缀和的做法时间复杂度为O(n)O(n)O(n) 使用树状数组时间复杂度降为O(logn)O(logn)O(logn) lowbit 1.x&(- ...

  3. 求序列最长不下降子序列_树状数组解决最长不下降子序列 讲讲主要思路就好...

    展开全部 不降子序列求的是一个元素的值单调e69da5e887aa62616964757a686964616f31333361306430不降的序列. 传统的状态设计便是使用f[n] 表示到达第n位时 ...

  4. HDU ACM 4031 Attack (树状数组--单点查询+区间更新)

    http://acm.hdu.edu.cn/showproblem.php?pid=4031 用了树状数组的区间更新 单点查找(一般为单点更新 区间查找) 例如 区间(2,4)加1 则Updata(2 ...

  5. 树状数组(单点+区间的所有操作)

    转载:https://blog.csdn.net/I_believe_CWJ/article/details/80374326 更简洁方便的数据结构--树状数组(基于线段树的实现) 1.单点更新+区间 ...

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

    一.树状数组是什么 树状数组,又称二进制索引树,英文名Binary Indexed Tree 之前遇到一个求逆序对的题,看了很多题解都只说了这个树状数组,关于怎么实现的全都避而不谈,我研究了一下午,总 ...

  7. 树状数组 _ 求逆序数

    注: 本文只是记录  ,您将从上面学习不到任何知识,除了 代码 (废话)第一次接触到树状数组,感觉接触到了新世界,理解这个思想用了好长时间,终于弄明白了(似懂非懂). 还有接触到了  离散化的思想, ...

  8. 逆序对(树状数组解决)

    传送门 Solution: 由于数字的大小可能非常大,而且都是未知的,所以只能采用离散化的方式先将数组离散化. 每次把这个数的位置加入到树状数组中,因为是排完序之后,所以之前加入的一定比后加入的大 然 ...

  9. P3368 【模板】树状数组 2(区间修改单点查询)

    这是树状数组的基础操作,和差分结合在一起,其实这种操作我更习惯于线段树的写法.不过树状数组代码短,执行效率高,值得记录一下. #include<bits/stdc++.h> #define ...

最新文章

  1. LeetCode简单题之数组拆分 I
  2. ClassLoader工作机制
  3. 帆软报表(finereport) 复选框多值查询
  4. InfoVista.NET 内部数据格式简介
  5. 大型 网站成长过程的分析笔记===通过广告来来学习,重要的是思路
  6. python使用redis实现session_redis与python交互session的redis存储配置
  7. 华龙电音基调网_华龙电音基调查询器下载(最好用的电音基调查询器) v1.4免费版...
  8. 这篇PLC编程教程,带你一步步入门PLC!
  9. 数字图像来源:光学成像系统
  10. qq飞车鸿蒙车队,qq飞车鸿蒙版
  11. vue单页面应用初始加载登录页_6 种 Vue 权限路由实现方式总结(最全)
  12. 北漂小斌和你分享古建筑斗拱木构件大样拆分图画法
  13. 【论文阅读】Image Super-Resolution Using Deep Convolutional Networks
  14. ​合并PDF文件什么方法很简单?看完你就明白了
  15. Python神经网络是这样识别手写字符哒?
  16. 谷歌黑搜索怎么收_谷歌搜索持久的反黑种族主义
  17. python 条形图填充疏密_Python数据分析 4:图表绘制工具Matplotlib
  18. Python的爬虫程序
  19. 企业飞信初探:无需APP也能聊天
  20. 数据库期末复习题总汇

热门文章

  1. r - 求平均成绩_2019深圳市公务员考试笔试成绩公布!
  2. 东软信息学院java试题,东软Java笔试题答案
  3. 网络传输模型(概念)
  4. 将中文日期转换成自己想要的格式如:2018年09月29日转换成2018-09-29
  5. 10-GLBP Weighting //2.1.5(GNS3版本,后面都是如此注明)
  6. __stdcall in c++ builder
  7. Asp.net Mvc 多级控制器 路由重写 及 多级Views目录 的寻找视图的规则 (多级路由) 如:Admin/Test/Index...
  8. C# ASP.NET 开发指引简要
  9. android 中的PopupWindow
  10. 浏览器打不开网页问题