可差分信息:如果知道部分的信息,用整体的信息和部分的信息就可以求出剩余部分的信息,那么这个信息是可差分的
P3374 【模板】树状数组 1 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include <iostream>
#include <vector>
using namespace std;
int n, m;
const int maxn = 500001;
int tree[maxn];
int lowbit(int i) {
return i & (-i);
}
void add(int i, int v) {//时间复杂度logn
while (i <= n) {
tree[i] += v;
i += lowbit(i);
}
}
int get_sum(int i) {//时间复杂度logn
int ans = 0;
while (i > 0) {
ans += tree[i];
i -= lowbit(i);
}
return ans;
}
int rangesum(int l,int r) {
return get_sum(r) - get_sum(l - 1);
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
int a;
cin >> a;
add(i, a);
}
vector<int>ans;
for (int i = 0; i < m; i++) {
int a, b, c;
cin >> a >> b >> c;
if (a == 1)
add(b, c);
else
ans.push_back(rangesum(b, c));
}
for (auto i : ans)
cout << i << endl;
return 0;
}
P3368 【模板】树状数组 2 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
维护其差分数组作为树状数组:这样范围增加相等于差分数组的单点增加;单点查询就可以用前缀和的方式求出
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class Main {
public static int MAXN = 500002;
// 树状数组不维护原数组的信息,维护原数组的差分信息
// 注意下标一定从1开始,不从0开始
public static int[] tree = new int[MAXN];
public static int n, m;
public static int lowbit(int i) {
return i & -i;
}
public static void add(int i, int v) {
while (i <= n) {
tree[i] += v;
i += lowbit(i);
}
}
// 返回1~i范围累加和
public static int sum(int i) {
int ans = 0;
while (i > 0) {
ans += tree[i];
i -= lowbit(i);
}
return ans;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer in = new StreamTokenizer(br);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
in.nextToken();
n = (int) in.nval;
in.nextToken();
m = (int) in.nval;
for (int i = 1, v; i <= n; i++) {
in.nextToken();
v = (int) in.nval;
add(i, v);
add(i + 1, -v);
}
for (int i = 1; i <= m; i++) {
in.nextToken();
int op = (int) in.nval;
if (op == 1) {
in.nextToken(); int l = (int) in.nval;
in.nextToken(); int r = (int) in.nval;
in.nextToken(); int v = (int) in.nval;
add(l, v);
add(r + 1, -v);
} else {
in.nextToken();
int index = (int) in.nval;
out.println(sum(index));
}
}
out.flush();
out.close();
br.close();
}
}
P3372 【模板】线段树 1 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
A1到Ak的所有数值的累加和可以通过差分分解为下述的表达式
所以维护好两个信息
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class Main {
public static int MAXN = 100001;
// 维护原始数组的差分信息:Di
public static long[] info1 = new long[MAXN];
// 维护原始数组的差分加工信息:(i-1) * Di
public static long[] info2 = new long[MAXN];
public static int n, m;
public static int lowbit(int i) {
return i & -i;
}
public static void add(long[] tree, int i, long v) {
while (i <= n) {
tree[i] += v;
i += lowbit(i);
}
}
public static long sum(long[] tree, int i) {
long ans = 0;
while (i > 0) {
ans += tree[i];
i -= lowbit(i);
}
return ans;
}
// 原始数组中[l..r]每个数值+v
public static void add(int l, int r, long v) {
add(info1, l, v);
add(info1, r + 1, -v);
add(info2, l, (l - 1) * v);
add(info2, r + 1, -(r * v));
}
// 原始数组中[l..r]范围上的累加和
public static long range(int l, int r) {
return sum(info1, r) * r - sum(info2, r) - sum(info1, l - 1) * (l - 1) + sum(info2, l - 1);
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer in = new StreamTokenizer(br);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
in.nextToken();
n = (int) in.nval;
in.nextToken();
m = (int) in.nval;
long cur;
for (int i = 1; i <= n; i++) {
in.nextToken();
cur = (long) in.nval;
add(i, i, cur);
}
long v;
for (int i = 1, op, l, r; i <= m; i++) {
in.nextToken();
op = (int) in.nval;
if (op == 1) {
in.nextToken(); l = (int) in.nval;
in.nextToken(); r = (int) in.nval;
in.nextToken(); v = (long) in.nval;
add(l, r, v);
} else {
in.nextToken(); l = (int) in.nval;
in.nextToken(); r = (int) in.nval;
out.println(range(l, r));
}
}
out.flush();
out.close();
br.close();
}
}
308. 二维区域和检索 - 矩阵可修改 - 力扣(LeetCode)
public class Code04_TwoDimensionSingleAddIntervalQuery {
class NumMatrix {
public int[][] tree;
public int[][] nums;
public int n;
public int m;
// 入参二维数组下标从0开始
// 树状数组一定下标从1开始
public NumMatrix(int[][] matrix) {
n = matrix.length;
m = matrix[0].length;
tree = new int[n + 1][m + 1];
nums = new int[n + 1][m + 1];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
update(i, j, matrix[i][j]);
}
}
}
private int lowbit(int i) {
return i & -i;
}
private void add(int x, int y, int v) {
for (int i = x; i <= n; i += lowbit(i)) {
for (int j = y; j <= m; j += lowbit(j)) {
tree[i][j] += v;
}
}
}
// 从(1,1)到(x,y)这个部分的累加和
private int sum(int x, int y) {
int ans = 0;
for (int i = x; i > 0; i -= lowbit(i)) {
for (int j = y; j > 0; j -= lowbit(j)) {
ans += tree[i][j];
}
}
return ans;
}
// 实际二维数组的位置是(x,y)
// 树状数组上的位置是(x+1, y+1)
// 题目说的是单点更新,转化成单点增加(老值-新值)即可
// 不要忘了在nums中把老值改成新值
public void update(int x, int y, int v) {
add(x + 1, y + 1, v - nums[x + 1][y + 1]);
nums[x + 1][y + 1] = v;
}
// 实际二维数组的位置是(x,y)
// 树状数组上的位置是(x+1, y+1)
public int sumRegion(int a, int b, int c, int d) {
return sum(c + 1, d + 1) - sum(a, d + 1) - sum(c + 1, b) + sum(a, b);
}
}
}
P4514 上帝造题的七分钟 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
从(1,1)到(n,m)的和经过推到得到下述的关系式
#include <cstdio>
using namespace std;
const int MAXN = 2050;
const int MAXM = 2050;
int info1[MAXN][MAXM], info2[MAXN][MAXM], info3[MAXN][MAXM], info4[MAXN][MAXM];
int n, m;
int lowbit(int i) {
return i & -i;
}
void add(int x, int y, int v) {
int v1 = v;
int v2 = x * v;
int v3 = y * v;
int v4 = x * y * v;
for (int i = x; i <= n; i += lowbit(i)) {
for (int j = y; j <= m; j += lowbit(j)) {
info1[i][j] += v1;
info2[i][j] += v2;
info3[i][j] += v3;
info4[i][j] += v4;
}
}
}
int sum(int x, int y) {
int ans = 0;
for (int i = x; i > 0; i -= lowbit(i)) {
for (int j = y; j > 0; j -= lowbit(j)) {
ans += (x + 1) * (y + 1) * info1[i][j] - (y + 1) * info2[i][j] - (x + 1) * info3[i][j] + info4[i][j];
}
}
return ans;
}
void add(int a, int b, int c, int d, int v) {
add(a, b, v);
add(c + 1, d + 1, v);
add(a, d + 1, -v);
add(c + 1, b, -v);
}
int range(int a, int b, int c, int d) {
return sum(c, d) - sum(a - 1, d) - sum(c, b - 1) + sum(a - 1, b - 1);
}
int main() {
char op;
int a, b, c, d, v;
scanf("%s", &op);
scanf("%d%d", &n, &m);
while (scanf("%s", &op) != EOF) {
if (op == 'X') {
scanf("%d%d", &n, &m);
} else if (op == 'L') {
scanf("%d%d%d%d%d", &a, &b, &c, &d, &v);
add(a, b, c, d, v);
} else {
scanf("%d%d%d%d", &a, &b, &c, &d);
printf("%d\n", range(a, b, c, d));
}
}
return 0;
}