来源:JK老班
题目:老师想知道从某某同学到某某同学当中,分数最高的是多少。
现在请你编程模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。
输入:
输入包含多组测试数据。
每组输入第一行是两个正整数N和M(0<N<=30000,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。
输出:
对于每一次询问操作,在一行里面输出最高成绩。
样例输入:
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
样例输出:
5 6 5 9
线段树建立:数组 或 二叉树的链式结构。
一般不是完全二叉树,不用数组,因为会浪费较多空间,但只有最后一层不是,也可以尝试,浪费不是很多。
链式二叉树,不用递归,难建,尤其是任意二叉树,完全二叉树还好些。
递归:只管你这层怎么做。
- 前半部分,递归,建好左子树,挂上来;
- 后半部分,递归,建好右子树,挂上来。
线段,是不是这个节点表示的:
- 是,return;
- 不是,三种情况。完全落在左半部分,去左孩子;完全落在右半部份,去右孩子;左,右都有分布,拆成2部分往下传。
import java.util.Scanner;
public class P1566 {
int[] A;
BTNode root;
public P1566(){
Scanner sc=new Scanner(System.in);
while(sc.hasNextInt()) {
int N=sc.nextInt(), M=sc.nextInt();
A=new int[N];
for(int i=0;i<N;i++) A[i]=sc.nextInt();
root=Build(0,N-1);
for(int i=0;i<M;i++) {
String C=sc.next(); int a=sc.nextInt(); int b=sc.nextInt();
if(C.equals("Q")) System.out.println(Query(a-1,b-1,root));
else Update(a-1,b,root);
}
}
}
//用递归建立二叉树
BTNode Build(int start,int end) {//返回根节点,参数为当前线段起点和终点
BTNode current=new BTNode();
current.L=start; current.R=end;
//线段就1个元素时
if(start==end) {
current.MAX=A[start];
return current;
}
int mid=(start+end)/2;
//建左右子树
current.left=Build(start,mid);//返回的根节点是左孩子
current.right=Build(mid+1,end);//返回的根节点是右孩子
current.MAX=Math.max(current.left.MAX, current.right.MAX);
return current;
}
int Query(int start,int end,BTNode current) {//要查的线段,现在在哪个节点
//你要查的线段是不是我这个节点表示的线段?
//是,直接返回
if(start==current.L && end==current.R) return current.MAX;
//不是,就有3种情况
int mid=(current.L+current.R)/2;
if(end<=mid) return Query(start,end,current.left);//1.要查的线段全在(当前节点表示的线段的)左孩子,往左
if(start>mid) return Query(start,end,current.right);//2.要查的线段全在右孩子,往右
return Math.max(Query(start,mid,current.left), Query(mid+1,end,current.right));//3.要查的线段左右都有分布,拆分
}
void Update(int index,int newValue,BTNode current) {
if(current.L==index && current.R==index) {
current.MAX=newValue;
return;
}
int mid=(current.L+current.R)/2;
if(index<=mid) Update(index,newValue,current.left);
else Update(index,newValue,current.right);
current.MAX=Math.max(current.left.MAX, current.right.MAX);
}
public static void main(String[] args) {
P1566 p=new P1566();
}class BTNode{//线段树的节点
int L,R;//线段
int MAX;//这个线段的最大值
BTNode left,right;//左右孩子
}
}