D. Program
大意:给出一段区间,区间从0开始不断进行+1或-1的操作,操作已经给出,问,删去一段操作之后,这段区间的最大值和最小值是多少
输入
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
输出
1
2
4
4
3
3
4
2
3
2
1
2
2
2
线框内的即为需要删掉的区间,
那么这道题的思路就是找到前一段的最大值和最小值,再找出后一段最大值最小值与后一段区间最前面那个点的差值,用前一段区间最大最小值加上这段差值,再与前一段的最大最小值比较大小就可以了
那么我们可以用前缀和与后缀和来保存区间的最大最小值,详看以下代码:
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
const int N = 2e5+10;
struct node
{
int minx;
int maxn;
}a[N];
struct node1
{
int minx;
int maxn;
}b[N];
int sum[N];
int sum1[N];
int main()
{
int t;
string s;
cin >> t;
while(t--)
{
int n, q, l, r, x = 0;
cin >> n >> q;
cin >> s;
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
memset(sum, 0, sizeof sum);
memset(sum1, 0, sizeof sum1);
for(int i=1; i<=n; i++)
{
if(s[i-1] == '-')
{
x--;
}
else if(s[i-1] == '+')
{
x++;
}
a[i].maxn = max(a[i-1].maxn, x);
a[i].minx = min(a[i-1].minx, x);
sum[i] = x;
}
x = 0;
for(int i=n; i>=1; i--)
{
if(s[i-1] == '-')
{
x--;
}
else if(s[i-1] == '+')
{
x++;
}
b[i].maxn = max(b[i+1].maxn, x);
b[i].minx = min(b[i+1].minx, x);
sum1[i] = x;
}
while(q--)
{
cin >> l >> r;
int ma, mi;
ma = sum1[r+1] - b[r+1].minx;
mi = b[r+1].maxn - sum1[r+1];
ma = max(a[l-1].maxn, sum[l-1] + ma);
mi = min(a[l-1].minx, sum[l-1] - mi);
mi = min(mi, 0);
ma = max(ma, 0);
printf("%d\n", ma-mi+1);
}
}
return 0;
}
需要注意的是,后缀和的最大值最小值刚好与正序的区间关于原点对称,所以最大最小值的差值需要反一下,这样即可求出答案