继续线段树水题。
求区间最大值,修改单个点。因为我还是采取的第一种建图方式,所以我修改单个点的话,比如修改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; }