D. Program
题意
给你一个\(x\)初始值为0,然后给你一系列\(+-\)操作,问你忽略掉\([l, r]\)区间的操作后,经过一系列操作,操作过程中会出现多少个不同的数字。比如说:0,1,2算三种,0,1, 0算2种
思路
容易发现一个区间\([x,y]\)其中出现的数的可能有\(max([x,y])-min([x,y])\)但是需要注意和0的关系问题,因为\(x\)的初始值为0。
三种情况分情况讨论:
[l,r]在最左部分也就是有效部分为[x,n],此时\(max([x,n]) - min([x, n])\)然后判断和0的关系
[l,r]在最右部分也就是有效部分为[1,x],此时\(max([1,x]) - min([1,x])\)然后判断和0的关系
如果[l,r在中间]那么我们将右面的部分减去[l,r]之间的影响值,也就是将左右两部分合并。
因为中间对右面的影响是固定值:\(a[r] - a[l - 1]\),然后同上和0讨论。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int lgn = 21;
//#define int long long
int qmax[N][21], qmin[N][21];
int lg[N];
void init() {
lg[1] = 0, lg[2] = 1;
for (int i = 3; i < N; ++i)lg[i] = lg[i >> 1] + 1;
}
void st(int n) {
for (int j = 1; j < lgn; ++j) {
for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
qmax[i][j] = max(qmax[i][j - 1], qmax[i+ (1 << (j - 1))][j - 1]);
qmin[i][j] = min(qmin[i][j - 1], qmin[i+ (1 << (j - 1))][j - 1]);
}
}
}
int lmax(int l, int r) {
int len = lg[r - l + 1];
return max(qmax[l][len], qmax[r - (1 << len) + 1][len]);
}
int lmin(int l, int r) {
int len = lg[r - l + 1];
return min(qmin[l][len], qmin[r - (1 << len) + 1][len]);
}
int psum[N];
int cal(int l1, int r1 ,int l2, int r2) {
r1 = max({r1, r2, 0});
l1 = min({l1 , l2, 0});
return r1 - l1 + 1;
}
void solve() {
int n, m; cin >> n >> m;
string str; cin >> str;
for (int i = 0; i < str.size(); ++i) {
if (str[i] == '+') psum[i + 1] = psum[i] + 1;
else psum[i + 1] = psum[i] - 1;
qmax[i + 1][0] = qmin[i + 1][0] = psum[i + 1];
}
st(n);
while (m --) {
int l, r; cin >> l >> r;
int l1, r1, l2, r2;
if (l == 1) {
l1 = 0;
r1 = 0;
} else {
l1 = lmin(1, l - 1);
r1 = lmax(1, l - 1);
}
if (r == n) l2 = 0, r2 = 0;
else {
l2 = lmin(r + 1, n);
r2 = lmax(r + 1, n);
l2 -= psum[r] - psum[l - 1];
r2 -= psum[r] - psum[l - 1];
}
cout << cal(l1 ,r1 ,l2 ,r2) << endl;
}
}
signed main() {
init();
ios::sync_with_stdio(false);
cin.tie(0);
int T = 1;
cin >> T;
while (T--) {
solve();
}
}