Matriz de árbol
Si tiene alguna pregunta, ¡hable en la sección de comentarios!
Introducción al problema
Enlace del título: HDU1166
n números, m operaciones.
Las operaciones son:
- Consulta ij (suma del intervalo de consulta [i, j])
- Sumar ij (aumentar j para el i-ésimo dígito)
- Sub ij (el número i-ésimo menos j)
Usar matriz de árbol
Para resolver este problema de manera simple y eficiente, necesitamos usar una matriz de árbol (por supuesto, también se puede usar un árbol de segmento de línea).
Portal de árbol de segmento de línea : árbol de segmento de línea
Entonces , ¿qué es una matriz de árbol? La matriz del árbol de simulación es una matriz de árbol ~ se mantiene la suma del prefijo.
como muestra la imagen.
Variables requeridas
Para la siguiente introducción, primero presentamos las variables requeridas.
int tree[N], a[N];
// tree[N]: 树状数组
// a[N] : 原数组
lowbit
Podemos (bu) y (neng) encontrar que la matriz de figuras anterior satisface las siguientes reglas:
árbol [1] = un [1] árbol [1] = un [1] t r e e [ 1 ]=un [ 1 ]
árbol [2] = un [1] + un [2] árbol [2] = a [1] + a [2]t r e e [ 2 ]=a [ 1 ]+un [ 2 ]
árbol [3] = un [3] árbol [3] = un [3]t r e e [ 3 ]=a [ 3 ]
árbol [4] = a [1] + a [2] + a [3] + a [4] árbol [4] = a [1] + a [2] + a [3] + a [ 4]t r e e [ 4 ]=a [ 1 ]+a [ 2 ]+a [ 3 ]+a [ 4 ]
规律 如下 :
árbol [i] = a [i - 2 k + 1] + a [i - 2 k + 2] +. . . + un árbol [i] [i] = a [i - 2 ^ k + 1] + a [i - 2 ^ k + 2] + ... + a [i]t r e e [ i ]=un [ yo-2k+1 ]+un [ yo-2k+2 ]+. . .+a [ i ]
dondekkk moneda yiisoy binarioDe menor a mayorLa longitud de ceros consecutivos.
por ejemplo:
Decimal | Binario | k |
---|---|---|
4 4 4 | 100 100 1 0 0 | 2 2 2 |
Por lo tanto, de la regla anterior, podemos obtener: árbol [4] = a [1] + a [2] + a [3] + a [4] árbol [4] = a [1] + a [2] + a [3] + a [4]t r e e [ 4 ]=a [ 1 ]+a [ 2 ]+a [ 3 ]+a [ 4 ] .
Lo que hace la matriz de árbol es simular esta regla y almacenar la suma del prefijo en la matriz de esta manera.
lograr
lowbit
// 比较简单的一个函数,是树状数组的灵魂所在
int lowbit(int x) {
// 返回x与上x的二进制中从右向左数第一位1变为0后的数字。
return x & (-x);
}
añadir
// 数组下标为 x 的元素增加 k
void add(int x, int k) {
// 不仅需要tree[x]增加k,也需要所有包含x的tree增加k
while (x <= n) {
tree[x] += k;
// 遍历寻找所有包含x的区间
x += lowbit(x);
}
}
consulta
// 查询区间 [1, x] 的和
int query(int x) {
int ans = 0;
// 如上面的图中所示,树状数组中的tree[x]很可能并非[1, x]的区间和,而只是[1, x]的子区间的区间和
while (x > 1) {
ans += tree[x];
// 遍历其它子区间
x -= lowbit(x);
}
}
Código completo
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<deque>
#include<vector>
#include<ctime>
using namespace std;
//#pragma GCC optimize(2)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ull unsigned long long
#define ll long long
#define rep(i, x, y) for(int i=x;i<=y;i++)
#define mms(x, n) memset(x, n, sizeof(x))
#define mmc(A, tree) memcpy(A, tree, sizeof(tree))
#define INF (0x3f3f3f3f)
#define mod (ull)(1e9+7)
typedef pair<int, int> P;
const int N = 1e5 + 10;
int n;
int tree[N], a[N];
char ch[10];
int lowbit(int x) {
return x & (-x);
}
void add(int x, int k) {
while (x <= n) {
tree[x] += k;
x += lowbit(x);
}
}
int query(int x) {
int ans = 0;
while (x >= 1) {
ans += tree[x];
x -= lowbit(x);
}
return ans;
}
int main() {
// freopen("input.txt", "r", stdin);
int T;
scanf("%d", &T);
for (int _ = 1; _ <= T; _++) {
mms(tree, 0);
mms(a, 0);
printf("Case %d:\n", _);
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
add(i, a[i]);
}
int c, d;
while (scanf("%s", ch) && ch[0] != 'E') {
scanf("%d%d", &c, &d);
if (ch[0] == 'A') {
add(c, d);
} else if (ch[0] == 'S') {
add(c, -d);
} else if (ch[0] == 'Q') {
int ans = query(d) - query(c - 1);
printf("%d\n", ans);
}
}
}
return 0;
}