P4192 Planejamento de viagens (bloqueio + casco convexo)
Assunto
Manter a sequência e apoiar duas operações
- Intervalo mais
- Soma máxima do prefixo da consulta de intervalo (refere-se a \ (\ sum_ {i = 1} ^ xa_i \) )
Intervalo de dados
Para dados de $ 100% $, $ n, m \ le 100000. $
Ideias de resolução de problemas
Bloco clássico
Considere somar diretamente o prefixo da sequência, que é equivalente ao intervalo mais a sequência aritmética, que é difícil de mesclar, e não é adequado usar a árvore de segmentos de linha; considere o bloqueio, porque uma sequência aritmética e outra sequência aritmética ou aritmética Portanto, cada bloco mantém duas tags (primeiro item, tolerância), representando a sequência aritmética adicionada por esse bloco, e podemos encontrar o valor de $ sum [i] $ por $ \ Theta (1) $,sum[i] = add[x] + d[x] * (i - L[x] + 1) + a[i]
Considere como consultar o bloco inteiro e encontre o ponto $ (i, soma [i]) $ com i como xe soma [i] como y. Faça um casco convexo para cada bloco. O ponto de contribuição deve estar no casco convexo e, após a operação do casco convexo ainda atingir o estado de pico único, você pode procurar no casco convexo por três pontos
O código é o seguinte
const int N = 200500;
int SIZ, BCNT;
int st[505][505], tp[505];
int L[N], R[N], bl[N];
ll add[N], a[N], d[N];
int m, n;
void spread(int x) {
if (!d[x] && !add[x]) return;
ll tmp = add[x];
for (int i = L[x]; i <= R[x]; ++i)
tmp += d[x], a[i] += tmp;
d[x] = add[x] = 0;
}
double K(int x, int y) {
return (double)(a[x] - a[y]) / (x - y);
}
void build(int x) {
spread(x); int *s = st[x], t = 0;
for (int i = L[x]; i <= R[x]; i++) {
while (t > 1 && K(s[t-1], s[t]) < K(s[t-1], i)) --t;
s[++t] = i;
}
tp[x] = t;
}
ll get(int x, int p) {
return (p - L[x] + 1) * d[x] + add[x] + a[p];
}
ll query(int x) {
int l = 1, r = tp[x], *s = st[x];
while (l <= r) {
int m1 = (l + r) >> 1, m2 = (m1 + r + 1) >> 1;
if (get(x, s[m1]) > get(x, s[m2])) r = m2 - 1;
else l = m1 + 1;
}
return get(x, s[r]);
}
int main() {
freopen ("hs.in","r",stdin);
freopen ("hs.out","w",stdout);
read(n); SIZ = sqrt(n), BCNT = n / SIZ;
if (BCNT * SIZ != n) BCNT++;
for (int i = 1;i <= n; i++) read(a[i]), a[i] += a[i-1];
for (int i = 1;i <= BCNT; build(i++)) {
L[i] = R[i-1] + 1, R[i] = min(R[i-1] + SIZ, n);
for (int j = L[i];j <= R[i]; j++) bl[j] = i;
}
for (read(m); m; m--) {
ll op, x, y, k;
read(op), read(x), read(y);
if (op) {
ll ans = -1e15;
spread(bl[x]), spread(bl[y]);
if (bl[y] - bl[x] <= 1) {
for (int i = x;i <= y; i++) Mx(ans, get(bl[i], i));
printf ("%lld\n", ans); continue;
}
for (int i = x;i <= R[bl[x]]; i++) Mx(ans, get(bl[i], i));
for (int i = bl[x] + 1; i < bl[y]; i++) Mx(ans, query(i));
for (int i = L[bl[y]];i <= y; i++) Mx(ans, get(bl[i], i));
printf ("%lld\n", ans);
}
else {
read(k); ll tmp = 0;
spread(bl[x]), spread(bl[y]);
if (bl[y] - bl[x] <= 1) {
for (int i = x;i <= y; i++) tmp += k, a[i] += tmp;
for (int i = y + 1;i <= R[bl[y]]; i++) a[i] += tmp;
for (int i = bl[y] + 1;i <= BCNT; i++) add[i] += tmp;
build(bl[x]), bl[x] != bl[y] && (build(bl[y]), 0);
continue;
}
for (int i = x; i <= R[bl[x]] ; i++) tmp += k, a[i] += tmp;
for (int i = bl[x] + 1; i < bl[y] ; i++) d[i] += k, add[i] += tmp, tmp += SIZ * k;
for (int i = L[bl[y]]; i <= y ; i++) tmp += k, a[i] += tmp;
for (int i = y + 1;i <= R[bl[y]]; i++) a[i] += tmp;
for (int i = bl[y] + 1;i <= BCNT; i++) add[i] += tmp;
build(bl[x]), build(bl[y]);
}
}
return 0;
}