P4192 Planejamento de viagens (bloqueio + casco convexo)

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;
}

Acho que você gosta

Origin www.cnblogs.com/Hs-black/p/12755104.html
Recomendado
Clasificación