开始刷线段树的题。上一道是单值加减,区间求和,我用树状数组过掉了。这道题是单值更新,区间求最值,只能用线段树了。
用了watashi翻译的那本书上的模版,把半闭半开的区间改成了全闭区间。另外数组开的大小问题还是不太懂。。
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <stack>
#include <algorithm>
#define MAXN 200005
#define MOD 1000000007
#define INF -2139062144
#define ll long long
//ios::sync_with_stdio(false)
using namespace std;
int N,M,mxn;
const int MAX_N = 1 << 18;
int dat[2*MAX_N-1];
void Init()
{
mxn=1;
while(mxn<N) mxn*=2;
memset(dat,0,sizeof(dat));
}
void update(int val,int k)
{
k+=mxn-1;//得到在线段树上的编号
dat[k]=max(val,dat[k]);//更改当前结点的值
while(k/2>0)//向上更新,父亲存在的时候
{
k=k/2;//父亲结点
dat[k]=max(dat[2*k],dat[2*k+1]);//父亲结点为左右孩子的较大值
}
}
int Query(int a,int b,int k,int l,int r)//闭区间
{
if(r<a||b<l) return 0;
if(a<=l&&r<=b) return dat[k];
else
{
int v1=Query(a,b,k*2,l,(l+r)/2);
int v2=Query(a,b,k*2+1,(l+r)/2+1,r);
return max(v1,v2);
}
}
int main()
{
while(scanf("%d%d",&N,&M)!=EOF)
{
Init();
for(int i=1; i<=N; ++i)
{
int t;
scanf("%d",&t);
update(t,i);
}
while(M--)
{
char str[5];
int a,b;
scanf("%s%d%d",str,&a,&b);
if(str[0]=='Q')
printf("%d\n",Query(a,b,1,1,mxn));
else update(b,a);
}
}
return 0;
}