Xiaobai visita el parque
Enlace de tema: ybt high -fficiency advanced 4-4-3 / luogu P4513
Idea general
Para darle una secuencia, hay dos operaciones que mantener.
Modificación de un solo punto y encontrar el peso del subintervalo con el mayor peso en un intervalo.
Ideas
De hecho, este es un enfoque de árbol de segmento de línea muy clásico.
Con solo buscar este intervalo, se puede dividir en un punto de división para encontrar el sufijo más grande en el frente y el sufijo más grande en la parte posterior, juntos, puede ser el más grande en este intervalo. (De lo contrario, debe ser el valor del intervalo separado por su punto de división)
Luego, pensará en usar el árbol de segmento de línea para mantener el sufijo de prefijo máximo y el peso total, y luego, a través de estas tres cosas, puede mantener el peso de subintervalo máximo.
Luego, al calcular la respuesta, si están en el mismo lado del punto de división, es fácil de decir, pero si no están en el mismo lado, debe averiguar los valores mantenidos arriba a la izquierda y a la derecha. lados y luego fusionarlos.
Debido a que los valores en estos dos lados pueden no estar en el árbol del segmento de línea, es mejor que su función devuelva la estructura de estos valores relacionados (para que sea conveniente y fácil de hacer).
Código
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
struct node {
ll x, lazy, lsum, rsum, sum;
}tree[4000001];
int n, m, a[500001];
int op, x, y;
void up(int now) {
tree[now].x = tree[now << 1].x + tree[now << 1 | 1].x;
tree[now].lsum = max(tree[now << 1].lsum, tree[now << 1].x + tree[now << 1 | 1].lsum);
tree[now].rsum = max(tree[now << 1 | 1].rsum, tree[now << 1 | 1].x + tree[now << 1].rsum);
tree[now].sum = max(max(tree[now << 1].sum, tree[now << 1 | 1].sum), tree[now << 1].rsum + tree[now << 1 | 1].lsum);
}
void build(int now, int l, int r) {
if (l == r) {
tree[now].x = a[l];
tree[now].lsum = tree[now].rsum = tree[now].sum = a[l];
return ;
}
int mid = (l + r) >> 1;
build(now << 1, l, mid);
build(now << 1 | 1, mid + 1, r);
up(now);
}
node get_sum(int now, int l, int r, int L, int R) {
if (L <= l && r <= R) {
return tree[now];
}
int mid = (l + r) >> 1;
node re;
//只存在于一遍
if (R <= mid) return get_sum(now << 1, l, mid, L, R);
if (mid + 1 <= L) return get_sum(now << 1 | 1, mid + 1, r, L, R);
//两边都有,就要想 up 一样比较
node re1= get_sum(now << 1, l, mid, L, R);
node re2 = get_sum(now << 1 | 1, mid + 1, r, L, R);
re.x = re1.x + re2.x;
re.lsum = max(re1.lsum, re1.x + re2.lsum);
re.rsum = max(re2.rsum, re2.x + re1.rsum);
re.sum = max(max(re1.sum, re2.sum), re1.rsum + re2.lsum);
return re;
}
void change_num(int now, int l, int r, int pl, int ch_num) {
if (l == r) {
tree[now].x = ch_num;
tree[now].lsum = tree[now].rsum = tree[now].sum = ch_num;
return ;
}
int mid = (l + r) >> 1;
if (pl <= mid) change_num(now << 1, l, mid, pl, ch_num);
else change_num(now << 1 | 1, mid + 1, r, pl ,ch_num);
up(now);
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
build(1, 1, n);
while (m--) {
scanf("%d %d %d", &op, &x, &y);
if (op == 1) {
if (x > y) swap(x, y);
printf("%lld\n", get_sum(1, 1, n, x, y).sum);
}
else change_num(1, 1, n, x, y);
}
return 0;
}