操作格子

蓝桥杯题目 ——操作格子


这题 用普通方法做呢 超时 只有50分,在这里我用了线段树来做,虽然AC了,但还不是很高效,本人渣渣,求指教!


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

//节点类
class Box {
	public int n;// 当前盒子结点是第n个结点
	public int left, right;// 区间
	public int sum, max;// 区间内的总和,以及最大值
	public Box leftchild, rightchild;// 该节点的左右孩子节点

	public Box(int left, int right, int n) {
		this.left = left;
		this.right = right;
		this.n = n;
	}
}

class BoxTree {

	public Box root;// 根节点

	public BoxTree(int left, int right, int n) {
		root = new Box(left, right, n);
		build_boxtree(left, right, n, root);// 调用创建树的方法
	}

	// 创建一棵树方法
	public void build_boxtree(int left, int right, int n, Box box) {

		if (left == right)// 当区间左右相等是出口
			return;
		
		int mid = (left + right) >> 1;// 获取区间的中点
		// 构建box节点的左孩子,left-mid是左孩子,mid+1-right是右孩子
		Box leftchild = new Box(left, mid, n << 1);
		box.leftchild = leftchild;
		build_boxtree(left, mid, n << 1, leftchild);

		// 构建box节点的右孩子
		Box rightchild = new Box(mid + 1, right, n << 1 + 1);
		box.rightchild = rightchild;
		build_boxtree(mid + 1, right, n << 1 + 1, rightchild);
	}

	// 挂值的方法,给每一个节点一个初始化值,通过这些值,可以确定每一个节点的最大值以及总和
	public void setvalue(Box box) throws IOException {

		// 获取用户输入的初始化值
		String values[] = ControlBox.br.readLine().split(" ");
		for (int i = 1; i <= values.length; i++) {
			int value = Integer.parseInt(values[i - 1]);
			while (box != null) {
				int left = box.left, right = box.right;
				// 此时的i是每一个节点的n
				if (left <= i && i <= right) {
					box.max = box.max < value ? value : box.max;
					box.sum += value;
				}

				int mid = (left + right) >> 1;
				if (i <= mid)
					box = box.leftchild;
				else
					box = box.rightchild;
			}
			// 因为每得到一个value呢,每一个节点的max和sum可能都有影响,所以,要重新从根节点开始更新max和sum
			box = root;
		}
	}

	// 修改节点的权值,那么这个方法就是更新max和sum的
	public void update(Box box, int n, int newvalue) {

		int left = box.left, right = box.right;
		// 当到达区间左右等于n的时候,该节点的最大值max和总和sum就是该新值newvalue
		if (left == n && n == right) {
			box.max = newvalue;
			box.sum = newvalue;
			return;
		} else {
			int mid = (left + right) >> 1;
			if (n <= mid)
				update(box.leftchild, n, newvalue);
			else
				update(box.rightchild, n, newvalue);

			// 对当前的box节点的max进行更新,在左右孩子中选出一个较大的max
			box.max = Math.max(box.leftchild.max, box.rightchild.max);
			// 对当前的box节点的sum进行更新,将其左右孩子相加,即和
			box.sum = box.leftchild.sum + box.rightchild.sum;
		}
	}

	// 获取指定区间内的总和的方法
	public int getSum(Box box, int x, int y) {

		int left = box.left, right = box.right;
		if (left == x && right == y)
			return box.sum;
		else {
			int mid = (left + right) >> 1;
			// 有三种可能
			if (y <= mid)// 第一种,区间[x,y]在mid的左边,那么找左孩子
				return getSum(box.leftchild, x, y);
			else if (mid < x)// 第二种,区间[x,y]在mid的右边,找右孩子
				return getSum(box.rightchild, x, y);
			// 第三种,则是mid的两边都有,那么将[x,y]分成两部分-[x,mid]+[mid+1,y]
			else
				return getSum(box.leftchild, x, mid) + getSum(box.rightchild, mid + 1, y);
		}
	}

	// 获取指定区间内的最大值max,其实是同getSum方法一样的道理
	public int getMax(Box box, int x, int y) {

		int left = box.left, right = box.right;
		if (left == x && right == y)
			return box.max;
		else {
			int mid = (left + right) >> 1;
			if (y <= mid)
				return getMax(box.leftchild, x, y);
			else if (mid < x)
				return getMax(box.rightchild, x, y);
			else
				return Math.max(getMax(box.leftchild, x, mid), getMax(box.rightchild, mid + 1, y));
		}
	}
}

public class ControlBox {

	public static BufferedReader br;
	public static List<Integer> result = new ArrayList<Integer>();

	public static void main(String[] args) throws IOException {

		br = new BufferedReader(new InputStreamReader(System.in));

		String order[] = br.readLine().split(" ");
		int n = Integer.parseInt(order[0]), m = Integer.parseInt(order[1]);

		BoxTree bt = new BoxTree(1, n, 1);// 一棵树在此诞生
		bt.setvalue(bt.root);// 初始化(挂值)

		// 操作
		for (int i = 0; i < m; i++) {
			String control[] = br.readLine().split(" ");
			int p = Integer.parseInt(control[0]);// 操作类型
			int x = Integer.parseInt(control[1]);
			int y = Integer.parseInt(control[2]);

			switch (p) {
			case 1:
				bt.update(bt.root, x, y);
				break;
			case 2:
				result.add(bt.getSum(bt.root, x, y));
				break;
			case 3:
				result.add(bt.getMax(bt.root, x, y));
				break;
			default:
				break;
			}
		}

		for (int i = 0; i < result.size(); i++) {
			System.out.println(result.get(i));
		}
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值