题目 D. Program
- 题意
x x x,初始为0,两种操作,’+’ 表示 x + = 1 x += 1 x+=1,’-’ 表示 x − = 1 x -= 1 x−=1。然后题目给出一系列操作。然后 q q q个询问 l , r l,r l,r。表示删掉区间 [ l − r ] [l-r] [l−r],之内的操作,剩下的操作,可以让x变成多少不同的值。
- 样例
8 4
− + − − + − − + -+--+--+ −+−−+−−+
1 8
2 8
2 5
1 1
样例解释:
1.empty program — x was only equal to 0;
2."-" — x had values 0 and −1;
3." − − − + ---+ −−−+" — x had values 0, −1, −2, −3, −2 — there are 4 distinct values among them;
4." + − − + − − + +--+--+ +−−+−−+" — the distinct values are 1, 0, −1, −2.
- 思路
很明显两个区间的最大值减去最小值+1就是有多少个数。
因为分为了两个空间,可以用前缀把左边区间 [ 1 , l − 1 ] ~[1,l-1]~ [1,l−1] 的最大值、最小值预先处理出来,用后缀把右边区间 [ r + 1 , n ] ~[r+1,n]~ [r+1,n] 的最大值、最小值预先处理出来,然后把右边区间的最大值、最小值减去中间的贡献,然后合并两个区间得到结果。
- 代码
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
char s[N];
int a[N],min1[N],max1[N],min2[N],max2[N];
int unite(int l1,int r1,int l2,int r2) // 区间合并 [l1,r1]与[l2,r2]
{
if(l1>l2)swap(l1,l2),swap(r1,r2);
return max(r1,r2)-l1+1;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--){
int n,m;
cin>>n>>m>>s+1;
int x=0;
min1[0]=0,max1[0]=0;
for(int i=1;i<=n;i++){
if(s[i]=='+')x++;
else x--;
a[i]=x;
min1[i]=min(min1[i-1],a[i]);
max1[i]=max(max1[i-1],a[i]);
}
min2[n+1]=a[n],max2[n+1]=a[n];
for(int i=n;i>=1;i--){
min2[i]=min(min2[i+1],a[i]);
max2[i]=max(max2[i+1],a[i]);
}
int l,r,ans;
while(m--){
cin>>l>>r;
int low1=min1[l-1];
int high1=max1[l-1];
int low2=min2[r+1];
int high2=max2[r+1];
int d=a[r]-a[l-1]; // 切去[l,r]区间后造成的变动值
if(l==1&&r==n)ans=1; // 全切
ans=unite(low1,high1,low2-d,high2-d);
printf("%d\n",ans);
}
}
return 0;
}
- 注:
官方给的题解和网上的一些也太难理解了,特别是0的处理,我实在是有点不太懂,然后看了这位老哥的题解感觉可以在他的基础上优化。因为根本不用处理0这个,你把贡献删掉之后,两个区间就会连续,最大值,最小值一减就会是答案。