#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+5;
int a[N];
struct node
{
int l;//控制a的左端点
int r;//控制a的右端点
int val;//计算题目中要求的值
}t[N*4];
//构造线段树 初始化t[]与a[]的映射关系
//bulid 1.t的id 2.a左端点 3.a右端点
void build(int p,int L,int R)
{
//0.初始化 初始当前节点p对应控制的a区间
t[p].l=L;t[p].r=R;//t[p]代表a[L,R]
//1.递归出口 当前节点为叶子 只有一个元素
if(L==R)
{//区间值就应该是元素值
t[p].val=a[L];
return;
}
//2.递归方程 分治算法 二分左右
int mid=t[p].l+t[p].r>>1;//构造时也可以写成L+R>>1
//只要节点p控制的元素数不为1一定存在子节点 递归构造左右子节点
build(p<<1,L,mid);//构造左孩子
build(p<<1|1,mid+1,R);//构造右孩子 p*2+1
//pushup操作 计算出子节点的val后 计算当前节点的val
t[p].val=max(t[p<<1].val,t[p<<1|1].val);
return;
}
//修改 change/update(单点修改更改a[x]的值/区间修改[x,y]的值为k)
//单点修改 1.正在维护的t[]id 2.修改对应的a[]id
void change(int p,int x)
{
//1.出口 如果当前t[]是个叶子 只有一个元素
if(t[p].l==t[p].r)
{
//修改当前的值为新的a[]
t[p].val=a[x];//这样写a[x]必须在主函数调用前提前维护好
return;
}
//2.方程 当前节点控制不止一个元素 一定有子节点
//找寻x在左或右子树上 二分查找逻辑
int mid=t[p].l+t[p].r>>1;
//在左子树上 修改左子树的值
if(x<=mid) change(p<<1,x);
//在右子树上 修改右子树的值
if(x>mid) change(p<<1|1,x);
//pushup操作 计算出子节点的val后 计算当前节点的val
t[p].val=max(t[p<<1].val,t[p<<1|1].val);
return;
}
//查询 query(查询某区间的值)
//1.当前查询的t[]元素id 2.查询a[]区间左端点 3.查询a[]区间右端点
int query(int p,int L,int R)
{
int maxx=-2e9;
//1.出口 当前节点控制的区间刚好是查询区间
if(t[p].l==L&&t[p].r==R)
{//直接返回当前记录的值即可
return t[p].val;
}
//2.方程 查询区间是否落在左右孩子上
int mid=t[p].l+t[p].r>>1;
int ans=0;//用来计算区间和
//查询目标区间一定与左孩子有交集满足:
if(L<=mid) maxx=max(maxx,query(p<<1,L,min(mid,R)));
//查询目标区间一定与右孩子有交集满足:
if(R>mid) maxx=max(maxx,query(p<<1|1,max(mid+1,L),R));
//返回最终求和的ans
return maxx;
}
signed main()
{
//定义输入信息
int n,m,x,y,k;
char op;
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",a+i);
//1.初始化(构造树) 从根开始构造 控制的是[1,n]
build(1,1,n);
//2.模拟过程
while(m--)
{
scanf(" %c",&op);
//根据操作 执行不同逻辑
if(op=='U')
{
//单点修改
scanf("%lld%lld",&x,&k);
if(a[x]<k)
{
a[x]=y;
change(1,x);
}
}
else
{
//区间查询
scanf("%lld%lld",&x,&y);
printf("%lld\n",query(1,x,y));
}
}
return 0;
}
ac会关注帮助我的大佬的!