You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
4.4 KiB

2 years ago
package class47;
// 同时支持范围增加 + 范围修改 + 范围查询的动态开点线段树(累加和)
// 真的用到!才去建立
// 懒更新,及其所有的东西,和普通线段树,没有任何区别!
public class Code02_DynamicSegmentTree {
public static class Node {
public int sum;
public int lazy;
public int change;
public boolean update;
public Node left;
public Node right;
}
public static class DynamicSegmentTree {
public Node root;
public int size;
public DynamicSegmentTree(int max) {
root = new Node();
size = max;
}
private void pushUp(Node c) {
c.sum = c.left.sum + c.right.sum;
}
private void pushDown(Node p, int ln, int rn) {
if (p.left == null) {
p.left = new Node();
}
if (p.right == null) {
p.right = new Node();
}
if (p.update) {
p.left.update = true;
p.right.update = true;
p.left.change = p.change;
p.right.change = p.change;
p.left.lazy = 0;
p.right.lazy = 0;
p.left.sum = p.change * ln;
p.right.sum = p.change * rn;
p.update = false;
}
if (p.lazy != 0) {
p.left.lazy += p.lazy;
p.right.lazy += p.lazy;
p.left.sum += p.lazy * ln;
p.right.sum += p.lazy * rn;
p.lazy = 0;
}
}
public void update(int s, int e, int v) {
update(root, 1, size, s, e, v);
}
private void update(Node c, int l, int r, int s, int e, int v) {
if (s <= l && r <= e) {
c.update = true;
c.change = v;
c.sum = v * (r - l + 1);
c.lazy = 0;
} else {
int mid = (l + r) >> 1;
pushDown(c, mid - l + 1, r - mid);
if (s <= mid) {
update(c.left, l, mid, s, e, v);
}
if (e > mid) {
update(c.right, mid + 1, r, s, e, v);
}
pushUp(c);
}
}
public void add(int s, int e, int v) {
add(root, 1, size, s, e, v);
}
private void add(Node c, int l, int r, int s, int e, int v) {
if (s <= l && r <= e) {
c.sum += v * (r - l + 1);
c.lazy += v;
} else {
int mid = (l + r) >> 1;
pushDown(c, mid - l + 1, r - mid);
if (s <= mid) {
add(c.left, l, mid, s, e, v);
}
if (e > mid) {
add(c.right, mid + 1, r, s, e, v);
}
pushUp(c);
}
}
public int query(int s, int e) {
return query(root, 1, size, s, e);
}
private int query(Node c, int l, int r, int s, int e) {
if (s <= l && r <= e) {
return c.sum;
}
int mid = (l + r) >> 1;
pushDown(c, mid - l + 1, r - mid);
int ans = 0;
if (s <= mid) {
ans += query(c.left, l, mid, s, e);
}
if (e > mid) {
ans += query(c.right, mid + 1, r, s, e);
}
return ans;
}
}
public static class Right {
public int[] arr;
public Right(int size) {
arr = new int[size + 1];
}
public void add(int s, int e, int v) {
for (int i = s; i <= e; i++) {
arr[i] += v;
}
}
public void update(int s, int e, int v) {
for (int i = s; i <= e; i++) {
arr[i] = v;
}
}
public int query(int s, int e) {
int sum = 0;
for (int i = s; i <= e; i++) {
sum += arr[i];
}
return sum;
}
}
public static void main(String[] args) {
int n = 1000;
int value = 50;
int createTimes = 5000;
int operateTimes = 5000;
System.out.println("测试开始");
for (int i = 0; i < createTimes; i++) {
int size = (int) (Math.random() * n) + 1;
DynamicSegmentTree dst = new DynamicSegmentTree(size);
Right right = new Right(size);
for (int k = 0; k < operateTimes; k++) {
double choose = Math.random();
if (choose < 0.333) {
int a = (int) (Math.random() * size) + 1;
int b = (int) (Math.random() * size) + 1;
int s = Math.min(a, b);
int e = Math.max(a, b);
int v = (int) (Math.random() * value);
dst.update(s, e, v);
right.update(s, e, v);
} else if (choose < 0.666) {
int a = (int) (Math.random() * size) + 1;
int b = (int) (Math.random() * size) + 1;
int s = Math.min(a, b);
int e = Math.max(a, b);
int v = (int) (Math.random() * value);
dst.add(s, e, v);
right.add(s, e, v);
} else {
int a = (int) (Math.random() * size) + 1;
int b = (int) (Math.random() * size) + 1;
int s = Math.min(a, b);
int e = Math.max(a, b);
int ans1 = dst.query(s, e);
int ans2 = right.query(s, e);
if (ans1 != ans2) {
System.out.println("出错了!");
System.out.println(ans1);
System.out.println(ans2);
}
}
}
}
System.out.println("测试结束");
}
}