树状数组求区间最大值(树状数组)(复习)

如题。

当遇到单点更新时,树状数组往往比线段树更实用。

算法:

设原数序列为a[i],最大值为h[i](树状数组)。

1。单点更新:

直接更新a[i],然后再更新h[i]。若h[i]的值有可能改变的,则表示区间一定包含i结点。那么就两层lowbit更新所有可能的h。

单点更新时间复杂度O(logn*logn)

 1 void update(int x)
 2 {
 3     while(x<=n)
 4     {
 5         h[x]=a[x];
 6         for(int i=1;i<lowbit(x);i<<=1)
 7         h[x]=max(h[x],h[x-i]);
 8         x+=lowbit(x);
 9     }
10     return ;
11 }

2。区间查询最大值:

设要查询的区间为[L,R],那么就从h[R]开始找,要找[L,R]内的所有区间。所以依然是两层lowbit,然后R向前跳直到跳到L前面。

区间查询最大值时间复杂度O(logn*logn)

 1 void findans(int begin,int end)
 2 {
 3     int ans=0;
 4     while(end>=begin)
 5     {
 6         ans=max(ans,h[end]);
 7         end--;
 8         for(;end-lowbit(end)>=begin;end-=lowbit(end))
 9         ans=max(ans,h[end]);
10     }
11
12     printf("%d\n",ans);
13     return ;
14 }

相关试题:hdu1754(单点修改,区间求最大值)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 const int maxn=300005;
 7 int h[maxn],a[maxn];
 8 int n,m;
 9 int lowbit(int x)
10 {
11     return x&(-x);
12 }
13 void update(int x)
14 {
15     while(x<=n)
16     {
17         h[x]=a[x];
18         for(int i=1;i<lowbit(x);i<<=1)
19         h[x]=max(h[x],h[x-i]);
20         x+=lowbit(x);
21     }
22     return ;
23 }
24 void findans(int begin,int end)
25 {
26     int ans=0;
27     while(end>=begin)
28     {
29         ans=max(ans,a[end]);
30         end--;
31         for(;end-lowbit(end)>=begin;end-=lowbit(end))
32         ans=max(ans,h[end]);
33     }
34
35     printf("%d\n",ans);
36     return ;
37 }
38 int main()
39 {
40     //freopen("in.txt","r",stdin);
41     //freopen("out.txt","w",stdout);
42     while(scanf("%d%d",&n,&m)==2)
43     {
44         memset(h,0,sizeof(h));
45         for(int i=1;i<=n;i++)
46         {
47             scanf("%d",&a[i]);
48             update(i);
49         }
50         for(int i=1;i<=m;i++)
51         {
52             char c=getchar();
53             while(c!=‘Q‘&&c!=‘U‘)c=getchar();
54             if(c==‘U‘)//update
55             {
56                 int y,z;
57                 scanf("%d%d",&y,&z);
58                 a[y]=z;
59                 update(y);
60                 continue;
61             }
62             if(c==‘Q‘)//findans
63             {
64                 int y,z;
65                 scanf("%d%d",&y,&z);
66                 findans(y,z);
67                 continue;
68             }
69         }
70     }
71
72     return 0;
73 } 
时间: 2024-10-06 12:15:07

树状数组求区间最大值(树状数组)(复习)的相关文章

树状数组求区间最大值

------  一直用 线段树 求区间最大值,想换种思路,用树状数组试试,肯定是可以的. 首先要对 树状数组的每个 i 所管理的区间有一定的理解.详见上篇博客: 树状数组(BIT)

hdu-1754 I Hate It【线段树】(求区间最大值)

题目链接:https://vjudge.net/contest/182746#problem/A I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)                                                    Total Submission(s): 96252    Accepted Submission(s): 36

树状数组求区间最值

树状数组求区间最值 树状数组(Binary Index Tree)利用二进制的一些性质巧妙的划分区间,是一种编程,时间和空间上都十分理想的求区间和的算法,同样我们可以利用树状数组优美的区间划分方法来求一个序列的最值 约定以 num[]  表示原数组, 以 idx[] 表示索引数组, Lowbit(x)=x&(-x) 树状数组求和时通过构造数组 idx[] 使 idx[k]=sum(num[tk]), tk [k-Lowbit(k)+1,k], 使用同样的方法构造最值索引数组: 以最大值为例, 先

2018中国大学生程序设计竞赛 - 网络选拔赛 1010 YJJ&#39;s Salesman 【离散化+树状数组维护区间最大值】

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6447 YJJ's Salesman Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 919    Accepted Submission(s): 290 Problem Description YJJ is a salesman who h

hdoj 2795 Billboard 【线段树 单点更新 + 维护区间最大值】

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 15719    Accepted Submission(s): 6629 Problem Description At the entrance to the university, there is a huge rectangular billboard of

POJ 2761 Feed the dogs(树状数组求区间第K大)

题目链接: 戳我 题目大意:Jiajia要为宠物狗,宠物狗按成一排站好(1 < i <= n),第 i 只狗的喜欢程度是 a[i], 之后他会先喂某个区间内第k个 即 n 个数, m个询问,接着是 n个数 接下来 m 行,每行是 l r k即 l 到 r 这个区间第 k 小的数,每个询问输出一个答案,即 a[i] 求区间第k大有很多算法, 详见此博客 [数据结构练习] 求区间第K大数的几种方法 我用的树状数组解法,来自 树状数组从前往后求和,用来解第k大(或小)的数 poj 2985 The

求数组所有区间最大值减去最小值之差的和(贝壳笔试题)

这个题直接暴力求解的话时间复杂度肯定是不行的,所以,我们要计算每个数值的贡献,对每一个数求他当最小值当了多少次,当最大值当了多少次,最后当最大值的次数乘以这个数值减去当最小值的次数乘以数值就得到这个数的贡献,依次把这n个数的贡献加起来就是整个极差之和. 在计算一个数当了多少最值的时候,我们要理解问题,因为区间是连续的,所以,以最小值为例,如果一个数是当前这段区间的最小值,那么他一定是当前这段区间最小的(这不废话),所以,我们就找到他往左做多能找到多少个连续的数都比他大,记录这个位置,同理找他右边

返回数组中的最大值和删除数组重复值-排序

//数组中最大值function getMax(arr){ //取该数组第一个值为最大值 var max=arr[0]; for(var i=0;i<arr.length;i++){ if(arr[i]>max){ max=arr[i] } } return max;} console.log(getMax([2,98,10,88])) /*--------------------------------------------------------------------*///删除数组重

【BZOJ1012】【树状数组求区间最值】最大数maxnumber

Description 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度. 2. 插入操作.语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾.限制:n是非负整数并且在长整范围内.注意:初始时数列是空的,没有一个数. Input 第一行两个整数,M和D,其中M表示操作