操作格子_蓝桥杯_线段树_java

这个题是,我想练习线段树找来做的。所以从一开始就知道它要用线段树来做。参考的是:https://blog.csdn.net/zearot/article/details/52280189,这个博主的线段树讲解。讲的很好。第一遍看不一定能看懂。多点耐心,慢慢来。最后肯定会理解的。好了,以下是“操作格子”的java代码。我主要是为了给自己记录的,哪里有错误或者问题,非常欢迎指出!因为我很菜的啦。。

package bluebridge2022;

import java.util.ArrayList;
import java.util.Scanner;

public class Operation_grid {
	static int maxn = 100007;  //元素总个数  
	static int Sum[] = new int[maxn<<2];//Sum求和,开四倍空间
	static int Max[] = new int[maxn<<2];//Sum求和,开四倍空间
	static int A[] = new int[maxn];//存原数组下标[1,n]
	int n;
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		int m = in.nextInt();
		for(int i = 1; i <= n; i++) {
			A[i] = in.nextInt();			
		}
		//创建线段树
		build(1,n,1);
		ArrayList<Integer> arr = new ArrayList<>();//存储答案的容器
		int ans = 0;
		for (int i = 0; i < m; i++) {
			int opera = in.nextInt();
			int x = in.nextInt();
			int y = in.nextInt();
			if(opera == 1) { //修改数值
				UpDate(x, y, 1, n, 1);
			}else if (opera == 2) { //求区间和
				ans = Query(x, y, 1, n, 1);
				arr.add(ans);
			}else { //求最大值
				ans = calMax(x,y,1,n,1);
				arr.add(ans);
			}
		}
		in.close();
		for(int i = 0; i <arr.size();i++) {
			System.out.println(arr.get(i));
		}
	}
	private static int calMax(int L, int R, int l, int r, int rt) {
		if(L <= l && r <= R) {	//如果现在这个区域在我想要计算的区域内,则返回这个区域的最大值
			return Max[rt];
		}
		int mid = (r+l) / 2;
		int temp1 = -1,temp2 = -1;//题目规定权值最小是0
		if(L <= mid) {//如果和左边有重叠的地方,得到重叠地方的最大值
			temp1 = calMax(L, R, l, mid, rt*2);
		}
		if(R > mid) {//如果和右边有重叠的地方,得到重叠地方的最大值
			temp2 = calMax(L, R, mid+1, r, rt*2+1);
		}		
		return Math.max(temp1, temp2);
	}
	//[L,R]是我想要计算的区域,[l,r]是当前区域
	private static int Query(int L, int R, int l, int r, int rt) {
		if(L <= l && r <= R) { //如果现在这个区域在我想要计算的区域内,则返回这个数值
			return Sum[rt];
		}
		int mid = (r+l) / 2;
		int ans = 0;
		if(L <= mid) {//左边有重叠的部分
			ans += Query(L, R, l, mid, rt*2);
		}
		if(R > mid) {//右边有重叠的部分
			ans += Query(L, R, mid+1, r, rt*2+1);
		}
		return ans;
	}
	private static void build(int l, int r, int rt) {
		if( r == l) { //将叶子结点信息填入
			Sum[rt] = A[l];
			Max[rt] = A[l];
			return;
		}
		int mid = (r+l) / 2;
		build(l, mid, rt*2);//创建左子树
		build(mid+1, r, rt*2+1);//创建右子树
		PushUp(rt);//更新数据   (当左右子树都创建完了之后才可以计算sum。因为sum的值就是由左右子树得来的)
	}
	private static void PushUp(int rt) {
		Max[rt] = Math.max(Max[rt*2], Max[rt*2+1]);//当前区域的最大值是左右子树区域的最大值的较大者
		Sum[rt] = Sum[rt*2] + Sum[rt*2 +1];//当前区域的和是左右子树(子区域)的和	
	}
	
	//把第i位数据改为k,当前边界为(l,r),当前结点为rt
	private static void UpDate(int i, int k, int l, int r, int rt) {
		if(l == r) {//到达叶节点,修改叶节点的值
			A[i] = k;//改写
			Sum[rt] = k;
			Max[rt] = k;
			return;
		}
		int mid = (r+l) / 2;
		//根据条件判断往左子树调用还是往右
		if( i <= mid) {
			UpDate(i, k, l, mid, rt*2);
		}else {
			UpDate(i, k, mid+1, r, rt*2+1);
		}
		//因为有元素改变了,所以要重新存一遍数据
		PushUp(rt);
		
	}


}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值