树状数组和线段树以前很少接触,特别是线段树,竞赛见到的次数还是不少的,今天就彻底搞明白一下。
首先是树状数组,时间O(logN),能解决的问题是快速求动态的前缀和,也就是动态改变数组的值以后求前缀和(单点修改,区间查询),树状数组解决的就这一类问题,不过解决起来代码量小,速度快;对比线段树,能解决的问题就很广泛了。
线段树相比较树状数组,能解决的问题不仅仅是前缀和的问题,什么最大值之类的都可以解决,但是代码相对麻烦一点。
模板题
Problem
这个是树状数组的模板函数
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw = new PrintWriter(System.out);
static int n, x, y, q;
static int a[], c[];
public static void main(String[] args) throws IOException {
String s[] = br.readLine().split(" ");
n = Integer.parseInt(s[0]);
q = Integer.parseInt(s[1]);
a = new int[n + 1];
c = new int[n + 1];
s = br.readLine().split(" ");
for (int i = 1; i <= n; i++) a[i] = Integer.parseInt(s[i - 1]);
for (int i = 1; i <= n; i++) add(i, a[i]);
while (q-- > 0) {
s = br.readLine().split(" ");
int handle = Integer.parseInt(s[0]);
int a = Integer.parseInt(s[1]);
int b = Integer.parseInt(s[2]);
if (handle == 1) add(a, b);
else pw.println(Sum(b) - Sum(a - 1));
}
pw.flush();
pw.close();
br.close();
}
public static void add(int x, int v) {
for (int i = x; i <= n; i += lowbit(i))
c[i] += v;
}
public static int lowbit(int x) {
return x & -x;
}
public static int Sum(int x) {
int res = 0;
for (int i = x; i > 0; i -= lowbit(i)) res += c[i];
return res;
}
}
线段树解决这道题:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw = new PrintWriter(System.out);
static int N = 100010, n, m;
static int w[] = new int[N];
static Node node[] = new Node[N * 4];
public static void main(String[] rags) throws IOException {
String s[] = br.readLine().split(" ");
n = Integer.parseInt(s[0]);
m = Integer.parseInt(s[1]);
s = br.readLine().split(" ");
for (int i = 1; i <= n; i++) w[i] = Integer.parseInt(s[i - 1]);
build(1, 1, n);
for (int i = 1; i <= m; i++) {
s = br.readLine().split(" ");
int k = Integer.parseInt(s[0]);
int a = Integer.parseInt(s[1]);
int b = Integer.parseInt(s[2]);
if (k == 0) pw.println(query(1, a, b));
else modify(1, a, b);
}
pw.flush();
pw.close();
br.close();
}
private static void modify(int u, int x, int v) {
if (node[u].getL() == node[u].getR()) node[u].setSum(node[u].getSum() + v);
else {
int mid = node[u].getL() + node[u].getR() >> 1;
if (x <= mid) modify(u << 1, x, v);
else modify(u << 1 | 1, x, v);
pushup(u);
}
}
private static int query(int u, int l, int r) {
if (node[u].getL() >= l && node[u].getR() <= r) return node[u].getSum();
int mid = node[u].getL() + node[u].getR() >> 1;
int sum = 0;
if (l <= mid) sum = query(u << 1, l, r);
if (r > mid) sum += query(u << 1 | 1, l, r);
return sum;
}
public static void build(int u, int l, int r) {
if (l == r) node[u] = new Node(l, r, w[r]);
else {
node[u] = new Node(l, r);
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
}
public static void pushup(int u) {
node[u].setSum(node[u << 1].getSum() + node[u << 1 | 1].getSum());
}
}
class Node {
private int l, r;
public void setL(int l) {
this.l = l;
}
public void setR(int r) {
this.r = r;
}
public void setSum(int sum) {
this.sum = sum;
}
private int sum;
public int getL() {
return l;
}
public int getR() {
return r;
}
public int getSum() {
return sum;
}
public Node(int l, int r, int sum) {
this.l = l;
this.r = r;
this.sum = sum;
}
public Node(int l, int r) {
this.l = l;
this.r = r;
}
}