Se le proporciona un programa que consta de nn instrucciones. Inicialmente, se asigna una sola variable xx a 00. Luego, las instrucciones son de dos tipos:
- aumentar xx en 11;
- disminuir xx en 11.
Recibirá consultas de mm con el siguiente formato:
- query ll rr - ¿a cuántos valores distintos se asigna xx si se ignoran todas las instrucciones entre el 11-ésimo y el rr-ésimo inclusive y el resto se ejecuta sin cambiar el orden?
Entrada
La primera línea contiene un solo entero tt (1≤t≤10001≤t≤1000) - el número de casos de prueba.
Luego sigue la descripción de los casos de prueba tt.
La primera línea de cada caso de prueba contiene dos números enteros nn y mm (1≤n, m≤2⋅1051≤n, m≤2⋅105): el número de instrucciones en el programa y el número de consultas.
La segunda línea de cada caso de prueba contiene un programa - una cadena de nn caracteres: cada carácter es '+' o '-' - instrucción de incremento y decremento, respectivamente.
Cada una de las siguientes líneas de mm contiene dos números enteros ll y rr (1≤l≤r≤n1≤l≤r≤n): la descripción de la consulta.
La suma de nn en todos los casos de prueba no excede 2⋅1052⋅105. La suma de mm en todos los casos de prueba no excede 2⋅1052⋅105.
Salida
Para cada caso de prueba, imprima mm enteros: para cada consulta ll, rr imprima el número de valores distintos a los que se asigna la variable xx si se ignoran todas las instrucciones entre la ll-ésima y la rr-ésima inclusive y el resto se ejecuta sin cambiar el orden.
Ejemplo
entrada
Copiar
2
8 4
-+--+--+
1 8
2 8
2 5
1 1
4 10
+-++
1 1
1 2
2 2
1 3
2 3
3 3
1 4
2 4
3 4
4 4
salida
Copiar
1
2
4
4
3
3
4
2
3
2
1
2
2
2
Nota
Las instrucciones que quedan para cada consulta del primer caso de prueba son:
- programa vacío - xx solo era igual a 00;
- "-" - xx tenía valores 00 y −1−1;
- "--- +" - xx tenía valores 00, −1−1, −2−2, −3−3, −2−2 - hay 44 valores distintos entre ellos;
- "+ - + - +": los valores distintos son 11, 00, −1−1, −2−2.
Idea principal:
Darle un número x, hay n operaciones, cada operación puede hacer x + 1 o x-1, q veces preguntar, cada vez que se le pregunte si elimina la operación de [l, r], ¿en cuántos números puede convertirse x? .
solución:
Sea max el valor máximo que puede llegar a ser x durante el proceso, y min el valor mínimo que puede llegar a tener x durante el proceso. La respuesta es max-min + 1 .
Si no hay consulta, se puede realizar el valor máximo o mínimo mediante suma de prefijo, ahora si se elimina el intervalo continuo, se cuenta la contribución que trae.
Suponiendo que el intervalo eliminado es [L, R], el valor máximo / mínimo antes de L y el valor máximo / mínimo después de R se pueden obtener a través del árbol del segmento de línea . La diferencia es que el valor máximo / mínimo después de R se resta de [L , La contribución de R] es la suma del intervalo es el verdadero valor máximo / mínimo después de la eliminación .
Codigo aceptado
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define sc scanf
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))
typedef long long ll;
const int Mod = 1e9 + 7;
const int N = 2e5 + 100;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % Mod; b >>= 1; t = (t*t) % Mod; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }
int mx[N * 4], mi[N * 4];
int pre[N], n, m;
char s[N];
#define ls (o << 1)
#define rs (ls | 1)
void Build(int o, int L, int R) {
if (L == R)
mx[o] = mi[o] = pre[L];
else {
int mid = (L + R) >> 1;
Build(ls, L, mid), Build(rs, mid + 1, R);
mx[o] = max(mx[ls], mx[rs]);
mi[o] = min(mi[ls], mi[rs]);
}
}
int Ask_Mx(int o, int L, int R, int l, int r) {
if (L >= l && R <= r)
return mx[o];
else {
int mid = (L + R) >> 1, ans = -INF;
if (mid >= l)
Max(ans, Ask_Mx(ls, L, mid, l, r));
if (mid < r)
Max(ans, Ask_Mx(rs, mid + 1, R, l, r));
return ans;
}
}
int Ask_Mi(int o, int L, int R, int l, int r) {
if (L >= l && R <= r)
return mi[o];
else {
int mid = (L + R) >> 1, ans = INF;
if (mid >= l)
Min(ans, Ask_Mi(ls, L, mid, l, r));
if (mid < r)
Min(ans, Ask_Mi(rs, mid + 1, R, l, r));
return ans;
}
}
int main()
{
#ifdef OlaMins
freopen("D:/input.txt", "r", stdin);
//freopen("D:/output.txt", "w", stdout);
#endif
int T; cin >> T;
while (T--) {
sc("%d %d %s", &n, &m, s + 1);
for (int i = 1; i <= n; i++)
pre[i] = pre[i - 1] + (s[i] == '+' ? 1 : -1); // 前缀和
Build(1, 1, n);
while (m--) {
int l, r, mx1 = 0, mi1 = 0;
sc("%d %d", &l, &r);
if (l > 1) {
Max(mx1, Ask_Mx(1, 1, n, 1, l - 1)); // L之前的答案可以直接得到
Min(mi1, Ask_Mi(1, 1, n, 1, l - 1));
}
if (r < n) { // R之后的答案要减去区间LR的贡献
Max(mx1, Ask_Mx(1, 1, n, r + 1, n) - pre[r] + pre[l - 1]);
Min(mi1, Ask_Mi(1, 1, n, r + 1, n) - pre[r] + pre[l - 1]);
}
printf("%d\n", mx1 - mi1 + 1);
}
}
return 0; // 改数组大小!!!用pair改宏定义!!!
}