HDU 1166 敌兵布阵 (线段树基础&树状数组基础)

题目链接

线段树和树状数组,都是用来维护区间信息的,并且都有较高的效率来查询(都是logn级,但树状数组在效率上还是略快于线段树)或者修改信息。

线段树在建树的时候,要开4倍的空间。 树状数组只需要另开一个维护数组。

线段树的代码更繁琐,但它可以区间更新,而树状数组只能单点更新。

因此,当题目不需要区间更新的时候,树状数组优先,反之则只能用线段树。

 

通过HDU 1166这题可以体会线段树和树状数组的基础。当然这题这两种都能用的原因是不需要区间更新。

由于我用Java,一般的Scanner 超时,因此改用了BufferedReader来输入,代码也麻烦了点

树状数组代码:

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
	static Scanner sc = new Scanner(System.in);
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
	static int T,n,cnt;
	static int [] sum = new int[50010];
	static String [] op = new String[3];
	static String [] num;
	static void add(int k, int val){
		while(k <= n){
			sum[k] += val; //加上更新的值
			k += k & -k;   //找到它的上一层
		}
	}
	static int sum(int k){
		int s = 0;
		while(k > 0){      //找到k的所有lowbit维护的区间,相加就是k维护的区间信息
			s += sum[k];   
			k -= k & -k;	
		}
		return s;
	}
	public static void main(String[] args) throws IOException {
		T = Integer.parseInt(bf.readLine());
		for(int t = 1; t <= T; t++){
			System.out.println("Case "+t+":");
			n = Integer.parseInt(bf.readLine());
			Arrays.fill(sum, 0);
			num = bf.readLine().split(" ");
			for(int i = 1; i <= n; i++){//初始化
				add(i,Integer.parseInt(num[i-1]));
			}
			while(true){
				op = bf.readLine().split(" ");
				if(op[0].equals("End")) break;
				if(op[0].equals("Query")){
					System.out.println(sum(Integer.parseInt(op[2]))-sum(Integer.parseInt(op[1])-1));
				}
				else if(op[0].equals("Add")){
					add(Integer.parseInt(op[1]),Integer.parseInt(op[2]));
				}
				else{
					add(Integer.parseInt(op[1]),-Integer.parseInt(op[2]));
				}
			}
		}
		
	}

}
	

 

 

 

线段树代码:

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

public class Main {
	static Scanner sc = new Scanner(System.in);
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
	static int T,n,cnt;
	static int [] tree;
	static String [] op = new String[3];
	static String [] num;
	static void init(int l, int r, int cur) throws IOException{
		if(l == r){//叶子结点
			tree[cur] = Integer.parseInt(num[cnt++]);
			return ;
		}
		int m = (l + r) >> 1;//(l+r)/2 
		init(l, m, cur << 1);//init左子树
		init(m+1, r, cur << 1 | 1);//init右子树
		tree[cur] = tree[cur << 1] + tree[cur << 1 | 1];//该点和为左右子树的和
	}
	static int query(int rt, int l, int r, int i, int j){//lr 为当期得到的范围, ij为需要查的范围
		if(l >= i && r <= j) return tree[rt];//范围内,直接return
		int m = (l + r) / 2;//缩小范围
		int ans = 0;
		//查左右
		if(i <= m) ans += query(rt << 1, l, m, i, j);//中间值大于m,说明还i还在外面,因此要继续查左子树
		if(j > m) ans += query(rt << 1 | 1, m + 1, r, i, j);//同上
		return ans;
	}
	static void update(int rt, int l, int r, int x, int val){
		if(l == r) {tree[rt] += val; return;}
		int m = (l + r) / 2;
		if(x <= m) update(rt << 1, l, m, x, val);//x在左边
		else update(rt << 1 | 1, m+1, r, x,val);//x在右边
		tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];//更新x影响的父节点值
	}
	public static void main(String[] args) throws IOException {
		T = Integer.parseInt(bf.readLine());
		for(int t = 1; t <= T; t++){
			cnt = 0;
			System.out.println("Case "+t+":");
			n = Integer.parseInt(bf.readLine());
			num = new String[n];
			num = bf.readLine().split(" ");
			tree = new int[4*n+1];
			init(1,n,1);
			while(true){
				op = bf.readLine().split(" ");
				if(op[0].equals("End")) break;
				int a = Integer.parseInt(op[1]), b = Integer.parseInt(op[2]);
				if(op[0].equals("Query")){
					System.out.println(query(1,1,n,a,b));
				}
				else if(op[0].equals("Add")){
					update(1,1,n,a,b);
				}
				else{//sub
					update(1,1,n,a,-b);
				}
			}
		}
		
	}

}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值