概述
用一个数组s来存放原始数组,用数组tree来存树状数组。
每次单点修改,都将受影响的s和tree的值修改,时间复杂度为O(logn).
每次区间查询[l,r]的最大值,如果区间长度大于lowbit(r)就一次性跨越一个lowbit(r)来查询,否则就一个点一个点的跨越。把查询过程看作砍柴:
砍一个点、砍一段区间(砍完至少剩一个点)、砍一段区间、砍一段区间…、
剩下的部分不足一段区间+一个点的时,一个点一个点的砍。
砍一个区间用tree,砍一个点用s。
单点修改
//将第i位的值修改为d
void update(int i,int d)
{
s[i]=d;//修改第i位的值
while(i<=N)//修改tree数组中的值
{
tree[i]=max(tree[i],d);
i+=lowbit(i);
}
}
区间查询最大值
//查询区间[l,r]的最大值
int query(int l,int r)
{
int ans=s[r];//砍一个点
while(l!=r)
{
//剩余部分够一个区间+一个点
for(--r;r>=l+lowbit(r);r-=lowbit(r))
{
ans=max(ans,tree[r]);//砍一个区间
}
//剩余部分不够一个区间+一个点
ans=max(ans,s[r]);//一个点一个点的砍直到r=l,通过for循环中--r去递减。
}
return ans;
}
例题
//HDU1754
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=2e5+100;
int tree[maxn],s[maxn],N;
int lowbit(int i)
{
return i&(-i);
}
void update(int i,int d)
{
s[i]=d;
while(i<=N)
{
tree[i]=max(tree[i],d);
i+=lowbit(i);
}
}
int query(int l,int r)
{
int ans=s[r];
while(l!=r)
{
for(--r;r>=l+lowbit(r);r-=lowbit(r))
{
ans=max(ans,tree[r]);
}
ans=max(ans,s[r]);
}
return ans;
}
int main()
{
int M;
while(~scanf("%d%d",&N,&M))
{
memset(s,0,sizeof(s));
memset(tree,0,sizeof(tree));
for(int i=1;i<=N;i++)
{
int a;
scanf("%d",&a);
s[i]=a;
update(i,a);
}
while(M--)
{
char C[10];
int x,y;
scanf("%s%d%d",C,&x,&y);
if(C[0]=='Q') printf("%d\n",query(x,y));
else update(x,y);
}
}
return 0;
}