用树状数组解决求区间最值的问题:hdu1754
以前都学过树状数组,但是已经差不多忘记了!不过看一看后,马上就都回忆起来了!而且感觉经过这么久的学习,对树状数组有了更深一层的领悟!个人觉得树状数组在本质上与线段树是没有区别的!都是管理区间,只不过树状数组管理区间的方式不一样罢了!
经过了解后就学习着解决hdu1754那道水题吧!我在网上看到的代码多半是用线段树解决的!这里把用色树状数组的解决代码贴出来吧!
7097586 | 2012-11-06 16:32:30 | Accepted | 1754 | 593MS | 2620K | 1524 B | C++ | xiaoshuai |
- #include<stdio.h>
- #include<string.h>
- #include<algorithm>
- #define M 200005
- using namespace std;
- int a[M];
- int Max[M];
- int hash[M];
- int n,m;
- int lowbit(int x){
- return x&(-x);
- }
- void build(int pos,int val){
- while(pos<=n){
- if(hash[pos]==0){
- Max[pos]=val;
- hash[pos]++;
- }else{
- Max[pos]=max(Max[pos],val);
- }
- pos+=lowbit(pos);
- }
- }
- void update(int pos,int val){
- //修改这元素 影响到的空间的值
- int i,j,k;
- a[pos]=val;//修改原始数组的值
- for(i=pos;i<=n;i+=lowbit(i)){
- Max[i]=a[i];
- if(lowbit(i)>1){
- for(j=i-1,k=i-lowbit(i)+1;j>=k;j-=lowbit(j)){
- Max[i]=max(Max[i],Max[j]);
- }
- }
- }
- }
- int query(int ll,int rr){
- int ans=a[rr];
- while(true){
- ans=max(ans,a[rr]);
- if(ll==rr)break;
- for(rr-=1;rr-ll>=lowbit(rr);rr-=lowbit(rr)){
- ans=max(ans,Max[rr]);
- }
- }
- return ans;
- }
- int main(){
- int i;
- char s[2];
- int ll,rr;
- int ans;
- while(scanf("%d %d",&n,&m)!=EOF){
- memset(hash,0,sizeof(hash));
- for(i=1;i<=n;i++){
- scanf("%d",&a[i]);
- build(i,a[i]);
- }
- for(i=0;i<m;i++){
- scanf("%s %d %d",s,&ll,&rr);
- if(s[0]=='U'){
- update(ll,rr);
- }else{
- ans=query(ll,rr);
- printf("%d\n",ans);
- }
- }
- }
- return 0;
- }
尽管这道题是如此简单,但是依然花了我大半天的时间!看来自己的代码能力还是需要提高啊!查询的方法是借鉴了(博客现在找不到了)!把原始数据加进去操作和更新的操作是我自己写的! 说实话,看懂与自己拍出来的差距真的挺大的!
特别是加入数据的操作,最开始学习树状数组是用电子科大的PPT里面的例子!
就是区间求和:
- #include<stdio.h>
- #include<string.h>
- int n=5;
- int a[6]={0,1,2,3,4,5};
- int sum[6];
- int lowbit(int t){
- return t&-t;
- }
- void update(int pos,int val){
- while(pos<=n){
- sum[pos]+=val;
- pos+=lowbit(pos);
- }
- }
- int query(int pos){
- int ans=0;
- while(pos>0){
- ans+=sum[pos];
- pos-=lowbit(pos);
- }
- return ans;
- }
- int main(){
- memset(sum,0,sizeof(sum));
- for(int i=1;i<=n;i++){
- update(i,a[i]);
- }
- int ans=query(5);
- printf("ans=%d\n",ans);
- return 0;
- }
当时我的思路也仅限于 用数状数组来求和! 学习线段树的时候,求和与求最大值几乎是没有区别的!但是用树状数组我就一下子转不过来了!转不过来的时候,一定要弄清楚的是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代码如下:
- void update(int pos,int val){
- int i,j,k;
- a[pos]=val;//修改原始数组的值
- for(i=pos;i<=n;i+=lowbit(i)){ //修改这元素 影响到的空间的值
- Max[i]=a[i];//由于a[i]的值已经变化,所以Max[i]的值可能不再是原来的值,需要我们重新求
- if(lowbit(i)>1){//这里k=i-lowbit(i)+1,表示下标i管理的区间的起点即i下标管理区间[k,i]
- for(j=i-1,k=i-lowbit(i)+1;j>=k;j-=lowbit(j)){
- Max[i]=max(Max[i],Max[j]);
- }
- }
- }
- }
学习算法是一个悟的过程!所谓“觉悟”,觉是一个瞬间,悟是一个过程。把所有的觉的瞬间,与长长一生的悟结合起来,你所到达的就是终于看见我的心。这是人生的的觉悟。
慢慢接着悟吧!
用树状数组解决求区间最值的问题:hdu1754相关推荐
- 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 ...
- 树状数组(求子区间和+更新元素值)
树状数组 欲完成修改值和查询区间和两种操作 求前缀和的做法时间复杂度为O(n)O(n)O(n) 使用树状数组时间复杂度降为O(logn)O(logn)O(logn) lowbit 1.x&(- ...
- 求序列最长不下降子序列_树状数组解决最长不下降子序列 讲讲主要思路就好...
展开全部 不降子序列求的是一个元素的值单调e69da5e887aa62616964757a686964616f31333361306430不降的序列. 传统的状态设计便是使用f[n] 表示到达第n位时 ...
- HDU ACM 4031 Attack (树状数组--单点查询+区间更新)
http://acm.hdu.edu.cn/showproblem.php?pid=4031 用了树状数组的区间更新 单点查找(一般为单点更新 区间查找) 例如 区间(2,4)加1 则Updata(2 ...
- 树状数组(单点+区间的所有操作)
转载:https://blog.csdn.net/I_believe_CWJ/article/details/80374326 更简洁方便的数据结构--树状数组(基于线段树的实现) 1.单点更新+区间 ...
- 树状数组(求逆序对)
一.树状数组是什么 树状数组,又称二进制索引树,英文名Binary Indexed Tree 之前遇到一个求逆序对的题,看了很多题解都只说了这个树状数组,关于怎么实现的全都避而不谈,我研究了一下午,总 ...
- 树状数组 _ 求逆序数
注: 本文只是记录 ,您将从上面学习不到任何知识,除了 代码 (废话)第一次接触到树状数组,感觉接触到了新世界,理解这个思想用了好长时间,终于弄明白了(似懂非懂). 还有接触到了 离散化的思想, ...
- 逆序对(树状数组解决)
传送门 Solution: 由于数字的大小可能非常大,而且都是未知的,所以只能采用离散化的方式先将数组离散化. 每次把这个数的位置加入到树状数组中,因为是排完序之后,所以之前加入的一定比后加入的大 然 ...
- P3368 【模板】树状数组 2(区间修改单点查询)
这是树状数组的基础操作,和差分结合在一起,其实这种操作我更习惯于线段树的写法.不过树状数组代码短,执行效率高,值得记录一下. #include<bits/stdc++.h> #define ...
最新文章
- LeetCode简单题之数组拆分 I
- ClassLoader工作机制
- 帆软报表(finereport) 复选框多值查询
- InfoVista.NET 内部数据格式简介
- 大型 网站成长过程的分析笔记===通过广告来来学习,重要的是思路
- python使用redis实现session_redis与python交互session的redis存储配置
- 华龙电音基调网_华龙电音基调查询器下载(最好用的电音基调查询器) v1.4免费版...
- 这篇PLC编程教程,带你一步步入门PLC!
- 数字图像来源:光学成像系统
- qq飞车鸿蒙车队,qq飞车鸿蒙版
- vue单页面应用初始加载登录页_6 种 Vue 权限路由实现方式总结(最全)
- 北漂小斌和你分享古建筑斗拱木构件大样拆分图画法
- 【论文阅读】Image Super-Resolution Using Deep Convolutional Networks
- ​合并PDF文件什么方法很简单?看完你就明白了
- Python神经网络是这样识别手写字符哒?
- 谷歌黑搜索怎么收_谷歌搜索持久的反黑种族主义
- python 条形图填充疏密_Python数据分析 4:图表绘制工具Matplotlib
- Python的爬虫程序
- 企业飞信初探:无需APP也能聊天
- 数据库期末复习题总汇
热门文章
- r - 求平均成绩_2019深圳市公务员考试笔试成绩公布!
- 东软信息学院java试题,东软Java笔试题答案
- 网络传输模型(概念)
- 将中文日期转换成自己想要的格式如:2018年09月29日转换成2018-09-29
- 10-GLBP Weighting //2.1.5(GNS3版本,后面都是如此注明)
- __stdcall in c++ builder
- Asp.net Mvc 多级控制器 路由重写 及 多级Views目录 的寻找视图的规则 (多级路由) 如:Admin/Test/Index...
- C# ASP.NET 开发指引简要
- android 中的PopupWindow
- 浏览器打不开网页问题