蓝桥杯题目 ——操作格子
这题 用普通方法做呢 超时 只有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));
}
}
}