继续线段树水题。
求区间最大值,修改单个点。因为我还是采取的第一种建图方式,所以我修改单个点的话,比如修改1这个点,对应的我的区间应该是[1,2](你完全可以想象成左闭右开嘛)。
这样的话,每个节点设置一个值,保存这棵子树的最大值。
更新的时候,回溯的时候更新父节点即可。查询的时候,比如查询1 3段,在我的程序中对应的是0 3 段。只要查到被0 3 段完全包含的区间,那么这个区间的最大值就要返回,和另一个被0 3 完全包含的区间的最大值进行对比即可。
G++1000+MS。。看status我以为是我的线段树写的效率这么低!后来搜题解的时候,发现说是C++比较快,交C++,500ms,中等水平吧。
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <climits>
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define MID(x,y) ((x+y)>>1)
using namespace std;
const int MAX = 200010;
struct Tnode{ int scr,l,r;};
Tnode node[MAX*4];
int c[MAX];
void init()
{
memset(node,0,sizeof(node));
}
void Build(int t,int l,int r)
{
node[t].l = l;
node[t].r = r;
if( l == r-1 )
{
node[t].scr = c[l];
return ;
}
int mid = MID(l,r);
Build(L(t),l,mid);
Build(R(t),mid,r);
node[t].scr = max(node[L(t)].scr,node[R(t)].scr);
}
void Updata(int t,int l,int r,int scr)
{
if( node[t].l == l && node[t].r == r )
{
node[t].scr = scr;
return ;
}
int mid = MID(node[t].l,node[t].r);
if( l >= mid )
Updata(R(t),l,r,scr);
else
if( r <= mid )
Updata(L(t),l,r,scr);
else
{
Updata(L(t),l,mid,scr);
Updata(R(t),mid,r,scr);
}
node[t].scr = max(node[L(t)].scr,node[R(t)].scr); // 父节点更新最大值
}
int Compute(int t,int l,int r)
{
if( node[t].l >= l && node[t].r <= r )
return node[t].scr;
int mid = MID(node[t].l,node[t].r);
if( l >= mid )
return Compute(R(t),l,r);
else
if( r <= mid )
return Compute(L(t),l,r);
else
return max(Compute(L(t),l,mid),Compute(R(t),mid,r));
}
int main()
{
int n,m,x,y;
char s[2];
while( ~scanf("%d%d",&n,&m) )
{
for(int i=0; i<n; i++)
scanf("%d",&c[i]);
init();
Build(1,0,n+1);
while( m-- )
{
scanf("%s%d%d",s,&x,&y);
if( s[0] == 'U' )
Updata(1,x-1,x,y);
else
{
int ans = Compute(1,x-1,y);
printf("%d\n",ans);
}
}
}
return 0;
}