这道题用到了线段树,之前看了相关的视频,对算法思路基本理解,但代码实现还有些困难,后来问了学长,自己又研究了一波,最后终于搞明白了。
线段树视频地址:https://www.bilibili.com/video/av44354587
线段树如图所示:
完整代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int tree[800010],a[200010],n,m,x;//用数组tree[]表示线段树,tree[p]是编号为p的结点所示区间中的最大值
void build(int p,int l,int r)//p是结点的编号,l和r为结点的左右边界
{
if(l==r)
{
tree[p]=a[l];
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);//这是回溯的创建过程
build(p*2+1,mid+1,r);
tree[p]=max(tree[2*p],tree[2*p+1]);//始终让当前结点保存其左右孩子中的最大值
}
int query(int p,int l,int r,int left,int right)//l,r是当前结点的左右边界;left,right是要查询的左右边界
{
if(l>=left&&r<=right)//在要查询的范围包括当前结点
{
return tree[p];
}
int mid=(l+r)/2;
if(right<=mid)//要查询的范围完全在左孩子所示区间内
{
return query(p*2,l,mid,left,right);
}
if(left>mid)//要查询的范围完全在右孩子所示区间内
{
return query(p*2+1,mid+1,r,left,right);
}
return max(query(p*2,l,mid,left,mid),query(p*2+1,mid+1,r,mid+1,right));//要查询的范围在左右孩子所示区间内都有
}
void update(int p,int l,int r,int x,int y)//x为要改的数,y为新的数
{
if(l==r)
{
tree[p]=y;
return;
}
int mid=(l+r)/2;
if(x<=mid)
{
update(p*2,l,mid,x,y);
}
else
{
update(p*2+1,mid+1,r,x,y);
}
tree[p]=max(tree[p*2],tree[p*2+1]);//始终让当前结点保存其左右孩子中的最大值
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
build(1,1,n);
char c;
int a,b;
while(m--)
{
getchar();
scanf("%c%d%d",&c,&a,&b);
if(c=='Q')
{
int maxnum=query(1,1,n,a,b);
printf("%d\n",maxnum);
}
else{
update(1,1,n,a,b);
}
}
}
}