思路
因为此题目中对于数的更新只能为 \(1\),所以,如果我们找到了 \([1,l - 1]\) 与 \([r + 1,n]\) 中能获得的两个极值即可。
我们为 \(S\) 赋予权值,用一个数组 \(a\) 储存:
- 如果 \(S_i\) 为
+
,则其权值为 \(1\)。 - 否则其权值为 \(-1\)。
那么,在第 \(i\) 次操作后,能产生的数是 \(\sum_{j = 1}^ia_j\)。
考虑用前缀和维护这个数,记作 \(s\)。
因为它是一个静态的问题,所以用 ST 表维护一下前缀和的极值。
对于前一部分(即 \([1,l - 1]\)),只需要求出 \(\max_{i \in [1,l - 1]}\{s_i\}\) 与 \(\min_{i \in [1,l - 1]}\{s_i\}\);对于后一部分,只需要求出 \(\max_{i \in [r + 1,n]}\{s_i\} - s_r + s_{l - 1}\) 与 \(\min_{i \in [r + 1,n]}\{s_i\} - s_r + s_{l - 1}\) 即可。(因为 \([l,r]\) 区间被忽略了)
此外,需要注意的是,如果 \(0\) 未包含在两个极值之间,需要将答案额外加上 \(1\)。
Code
#include <bits/stdc++.h>
#define re register
using namespace std;
const int N = 2e5 + 10,M = 25,inf = 0x3f3f3f3f;
int T,n,q;
int arr[N],lg[N + 10];
string s;
struct ST{
#define pot(x) (1 << x)
int dp1[N][M],dp2[N][M];//dp1 维护最小值,dp2 维护最大值
inline void init(){
for (re int j = 1;j <= lg[n];j++){
for (re int i = 1;i <= n - pot(j) + 1;i++){
dp1[i][j] = min(dp1[i][j - 1],dp1[i + pot(j - 1)][j - 1]);
dp2[i][j] = max(dp2[i][j - 1],dp2[i + pot(j - 1)][j - 1]);
}
}
}
inline int query_Min(int l,int r){
int x = lg[r - l + 1];
return min(dp1[l][x],dp1[r - pot(x) + 1][x]);
}
inline int query_Max(int l,int r){
int x = lg[r - l + 1];
return max(dp2[l][x],dp2[r - pot(x) + 1][x]);
}
#undef pot
}st;
inline void Log(){
lg[1] = 0;
for (re int i = 2;i <= N;i++) lg[i] = lg[i / 2] + 1;
}
inline int sum(int l,int r){
return arr[r] - arr[l - 1];
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> T;
Log();
while (T--){
cin >> n >> q >> s;
s = ' ' + s;
for (re int i = 1;i <= n;i++){//转化权值
if (s[i] == '+') arr[i] = arr[i - 1] + 1;
else arr[i] = arr[i - 1] - 1;
}
for (re int i = 1;i <= n;i++) st.dp1[i][0] = st.dp2[i][0] = arr[i];
st.init();
while (q--){
int l,r;
cin >> l >> r;
int l1 = 1,r1 = l - 1;
int l2 = r + 1,r2 = n;
int Min = inf,Max = -inf;
if (l1 <= r1){//避免出现 l = 1 的情况
Min = min(Min,st.query_Min(l1,r1));
Max = max(Max,st.query_Max(l1,r1));
}
if (l2 <= r2){//避免出现 r = n 的情况
Min = min(Min,st.query_Min(l2,r2) - sum(l,r));
Max = max(Max,st.query_Max(l2,r2) - sum(l,r));
}
if (Min == inf) Min = 0;//特判 l = 1 且 r = n 的情况
if (Max == -inf) Max = 0;
if (Min <= 0 && 0 <= Max) cout << (Max - Min + 1) << "\n";
else cout << (Max - Min + 2) << "\n";
}
}
return 0;
}
标签:CF1473D,int,题解,ST,Program,inf,极值
From: https://www.cnblogs.com/WaterSun/p/18264795