【线段树】操作格子
此题为线段树算法题,题目来源计科老班
题目描述
有n个格子,从左到右放成一排,编号为1-n。
共有m次操作,有3种操作类型:
1.修改一个格子的权值,
2.求连续一段格子权值和,
3.求连续一段格子的最大值。
对于每个2、3操作输出你所求出的结果。
输入
第一行2个整数n,m。
接下来一行n个整数表示n个格子的初始权值。
接下来m行,每行3个整数p,x,y,p表示操作类型,p=1时表示修改格子x的权值为y,p=2时表示求区间[x,y]内格子权值和,p=3时表示求区间[x,y]内格子最大的权值。
数据规模与约定
对于20%的数据n < = 100,m < = 200。
对于50%的数据n < = 5000,m < = 5000。
对于100%的数据1 < = n < = 100000,m < = 100000,0 < = 格子权值 < = 10000。
输出
有若干行,行数等于p=2或3的操作总数。
每行1个整数,对应了每个p=2或3操作的结果。
样例输入
4 3
1 2 3 4
2 1 3
1 4 3
3 1 4
样例输出
6
3
思路详解
由于数据规模大,如果从头开始遍历搜索树,效率慢并且复杂度高。因此将n个数分段查询,这样可以提高效率。已知n个数,其划分的线段不会超过log2n+1。
如何构建线段树?
使用递归方法来建立线段树,先递归建好左子树,再递归建好右子树。由于题目需要找寻最大值和权值和,因此建树时就将最大值和权值和保存在树的节点中。
代码
import java.util.Scanner;
public class LinearTreeP1382 {
int[] A;
BTNode root;
public LinearTreeP1382() {
int n,m;
Scanner sc = new Scanner(System.in);
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);
int p,x,y;
for(int i=0;i<m;i++) {
p = sc.nextInt();
x = sc.nextInt();
y = sc.nextInt();
switch(p) {
case 1:
Update(x-1, y, root);
break;
case 2:
System.out.println(Search(x-1, y-1, root));
break;
case 3:
System.out.println(SearchMax(x-1, y-1, root));
break;
}
}
}
BTNode Build(int start, int end) { //建立线段树
BTNode current = new BTNode();
current.L = start;
current.R = end;
if(start == end) {
current.sum = A[start];
current.max = A[start];
return current;
}
//不只一个数,有左右孩子
int mid = (start+end)/2;
current.left = Build(start,mid);
current.right = Build(mid+1, end);
current.sum = current.left.sum + current.right.sum;
current.max=Math.max(current.left.max,current.right.max);
return current;
}
//求权值和,p=2
int Search(int start, int end, BTNode current) {
if(start == current.L && end == current.R)
return current.sum;
int mid = (current.L+current.R)/2;
//都在左孩子
if(end <= mid)
return Search(start, end, current.left);
//都在右孩子
if(start > mid)
return Search(start, end, current.right);
//一部分在左孩子,一部分在右孩子
return Search(start, mid, current.left)
+Search(mid+1, end, current.right);
}
//更新权值,p=1
void Update(int index,int newvalue, BTNode current) {
if(current.L == index && current.R == index) {
current.sum=newvalue;
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.sum = current.left.sum + current.right.sum; //更新权值和
current.max=Math.max(current.left.max,current.right.max); //更新最大值
}
//求取最大值,p=3
int SearchMax(int start, int end, BTNode current) {
if(start == current.L && end == current.R)
return current.max;
int mid = (current.L+current.R)/2;
if(end <= mid)
return SearchMax(start, end, current.left);
if(start > mid)
return SearchMax(start, end, current.right);
return Math.max(SearchMax(start, mid, current.left),
SearchMax(mid+1, end, current.right));
}
public static void main(String[] args) {
LinearTreeP1382 l = new LinearTreeP1382();
}
class BTNode{ //线段树节点定义
int L,R; //L开始下标,R结束下标
int sum;
int max;
BTNode left;
BTNode right;
}
}