Problem Description
很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。
这让很多学生很反感。
不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。
这让很多学生很反感。
不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。
Input
本题目包含多组测试,请处理到文件结束。
在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目。
学生ID编号分别从1编到N。
第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。
接下来有M行。每一行有一个字符 C (只取'Q'或'U') ,和两个正整数A,B。
当C为'Q'的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为'U'的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目。
学生ID编号分别从1编到N。
第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。
接下来有M行。每一行有一个字符 C (只取'Q'或'U') ,和两个正整数A,B。
当C为'Q'的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为'U'的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
Output
对于每一次询问操作,在一行里面输出最高成绩。
Sample Input
5 6
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 2 9
Q 1 5
Sample Output
5
6
5
9
解题思路:这是线段树的一道入门题目,关于线段树的讲解,看看大牛之作吧,线段树详解 (原理,实现与应用) 每次看都有深刻的理解,好了,相关注解就看代码吧!
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std;//思路:将编号划分区间,进行建树,然后有数据的更新,删除,查询 3 const int maxn = 200005; 4 int a,b,q[maxn],t[maxn<<2];//a,b是操作数,q是存放学生成绩,t是建树的节点数,t数组的长度一般是原数据的长度的4倍,来记录区间的最大值 5 void build(int l,int r,int x)//建树 6 { 7 int mid=(l+r)>>1;//取中间值 8 if(l==r){//区间只有一个正数,即叶子节点的值就是q数组中保存的值 9 t[x]=q[mid]; 10 return; 11 } 12 build(l,mid,x<<1);//递归建立左子树2*x 13 build(mid+1,r,x<<1|1);//递归建立右子树2*x+1 14 t[x]=max(t[x<<1],t[x<<1|1]);//建立完左子树和右子树之后返回到父节点,此时父节点的值等于左右子树的最大值 15 } 16 int query(int l,int r,int x)//查询 17 {//[a,b]、[l,r] 18 if(a<=l && b>=r)return t[x];//如果该节点表示的区间恰好是要查询的区间,直接返回结果,即[l,r]是[a,b]的一个子集,直接返回最大值 19 else{ 20 int mid=(l+r)>>1; 21 if(b<=mid)return query(l,mid,x<<1);//判断(编号)区间在哪棵子树上[a,b]在[l,r]的左子树[l,mid]上 22 else if(a>mid)return query(mid+1,r,x<<1|1);//[a,b]在[l,r]的右子树[mid+1,r]上 23 else return max(query(l,mid,x<<1),query(mid+1,r,x<<1|1));//表示[a,b],有一部分在[l,mid]上,有一部分在[mid+1,r]上,直接返回左右区间的最大值 24 } 25 } 26 void modify(int l,int r,int x)//更新节点,更改值,x为编号 27 {//[l,r],此时的a为学生编号ID、b为成绩值 28 if(l==r){//找到叶子节点 29 t[x]=b;//把a的成绩改成b的成绩 30 return; 31 } 32 int mid=(l+r)>>1;//判断更新节点在哪棵树上 33 if(a<=mid){modify(l,mid,x<<1),t[x]=max(t[x<<1],t[x<<1|1]);}//如果编号a在[l,mid]上,递归修改,直到叶子节点,返回到父节点时,父节点保存左右子树的最大值 34 else{modify(mid+1,r,x<<1|1),t[x]=max(t[x<<1],t[x<<1|1]);}//同时更新节点的最大值 35 }//回溯的时候将所有的父节点给更新了 36 int main() 37 { 38 int m,n;char ch; 39 while(~scanf("%d %d",&n,&m)){ 40 for(int i=1;i<=n;++i)scanf("%d",&q[i]); 41 build(1,n,1);//建树 42 while(m--){ 43 getchar();//吃掉回车符的影响 44 scanf("%c %d %d",&ch,&a,&b); 45 if(ch=='Q')printf("%d ",query(1,n,1));//返回最大值 46 else modify(1,n,1);//进行修饰 47 } 48 } 49 return 0; 50 }