/*1 线段树可以看做是一个很特别的二叉树2 如果说父亲节点是n,那么两个孩子节点分别是2*n和2*n+1.这样理解很不错*/#include <iostream>using namespace std;#define MAX 600000//#define MAX 100struct Node{ int l,r,mid,max;}node[MAX];//获取最大值int max(int a,int b){ return a>b?a:b;}//初始化(其中参数n代表第几层,所以在调用的时候都写上1)void inint(int a,int b,int n){ node[n].l=a;//左边 node[n].max=-1;//最大值, node[n].r=b;//右边 node[n].mid=(a+b)/2;//中间值 //如果到倒数第二层返回 if(a+1==b)return; //建立左子树和右子树 inint(a,(a+b)/2,n*2); inint((a+b)/2,b,2*n+1);}//更新(pos是学生id,value是学生的分数)(这个应该是从顶开始的,不是从低开始的)(n表示第几层)void update(int pos,int value,int n){//如果说要插入的值,大于原来节点的最大值,那么就更新原来的值(一路上所有的点都更新了) if(value>node[n].max)node[n].max=value; //因为把这个线段树看做是左闭右开区间(所以这个条件代表达到最后一层,如果到达最后一层肯定返回) if((node[n].l+1)==node[n].r)return;//放入左子树 if(pos<node[n].mid) { update(pos,value,2*n); }//放入右子树 if(pos>=node[n].mid) { update(pos,value,2*n+1); }}//把a到为b之间的最大值找出来。n是node 的层次的值,也就是说节点的id,也就是说,调用函数的时候n==1//同时也可以认为n就是key值,因为第一层是1,第二层是2,3,第三层是4,5,6,7int query(int a,int b,int n){//如果说已经到了需要查找的一层 if( node[n].l==a && node[n].r==b)return node[n].max;//如果说a<node[n].mid不一定表示在左区间//表示在做区间肯定有一部分在,所以应该分开计算,左区间到node[n].mid,还有就是从node[n].mid+1到b的部分 if(a<node[n].mid) {//如果说完全在左区间 if(b<=node[n].mid) { return query(a,b,2*n); }//如果左区间有一部分,右区间也有一部分 else { return max(query(a,node[n].mid,2*n),query(node[n].mid,b,2*n+1));//后面的2*n和2*n+1代表下一个数组的层次。 } }//如果说右区间,就进入下一个二叉树的右子树 else { return query(a,b,2*n+1); }} int main(){//freopen("in.txt","r",stdin); int n,m,t,a,b,i; char ch; while(cin >>n>>m) {//初始化 inint(1,n+1,1);//输入n个学生的成绩 for(i=1;i<=n;i++) {scanf("%d",&t); update(i,t,1); } //开始查询 for(i=1;i<=m;i++) {getchar(); cin >>ch;//输入a和b的(左右区间) cin >>a>>b;//如果说是查询的话 if(ch=='Q')cout <<query(a,b+1,1)<<endl;//注意是b+1而不是b。因为线段树是一个左开右闭的的区间。//如果说是更新的话 elseupdate(a,b,1); } } return 0;}