Educational Codeforces Round 102 (Rated for Div. 2) D. Program
题意:有一个长度为n,只包含+ 和 -的字符串,+表示+1,-表示-1,x初始为0,有q次询问,每次询问输入一个区间表示该区间的符号忽略,问执行剩下的符号过程中出现几个不同的数
思路:线段树求区间最值,首先让 a[1]=0 ,然后利用 a数组进行构造线段树。这样就可以不用分类讨论了,只需要把在输入查询区间的时候把左右两个端点同时加一就可以了。(因为这样多在数组中塞了一个1)
l++,r++;
下面在查询的时候永远都会剩一个a[1]。
左区间 :在查询的时候直接查询区间 [ 1 , x - 1 ] 的最大和最小 就可以了。
右区间:在查询的时候直接查询区间 [ y + 1, n+1 ] 的最大和最小 就可以了。
注意右区间,这个时候需要减去区间 [ l , y ] 的贡献度。因为我们最开始的操作的时候是在区间 [ l , y ], 还存在的时候进行操作的,所以这个时候就要让右区间的最大和最小减去 [ l , y ] 的贡献度,得到没有区间 [ l , y ] 操作的真实值。、
int tp=a[r]-a[l-1]; Ma2-=tp; Mi2-=tp;
最后比较,左区间和右区间的的最大和最小,因为这两个区间必定是相连接的,所以不用进行分类讨论,直接比较大小就可以了。
int Max=max(Ma2,Ma1); int Min=min(Mi1,Mi2);
#include<bits/stdc++.h> using namespace std; const int N=2e5+10; typedef long long ll; ll a[N]; struct node{ ll l,r; // 左右区间的端点 ll Mi,Mx,lazy; //区间最大,最小,懒惰标记 ll sum,len; } tree[N<<2]; void pushup(int n){ tree[n].Mx=max(tree[n<<1].Mx,tree[n<<1|1].Mx); tree[n].Mi=min(tree[n<<1].Mi,tree[n<<1|1].Mi); } void pushdown(int n){ if(tree[n].lazy){ int val=tree[n].lazy; tree[n<<1].Mi=tree[n<<1].Mx=tree[n<<1].lazy=val; tree[n<<1|1].Mi=tree[n<<1|1].Mx=tree[n<<1|1].lazy=val; tree[n].lazy=0; } } void build_tree(int n,int l,int r){ tree[n].l=l; tree[n].r=r; tree[n].lazy=0; tree[n].len=r-l+1; if(l==r) tree[n].Mi=tree[n].Mx=tree[n].sum=a[l]; else{ ll mid=(l+r)/2; int left_node= 2*n; int right_node=2*n+1; build_tree(left_node,l,mid); build_tree(right_node,mid+1,r); pushup(n); } } int query_tree1(int n,int l,int r){ if(tree[n].l>=l&&tree[n].r<=r){ return tree[n].Mx; } pushdown(n); ll mid=(tree[n].l+tree[n].r)/2; ll ans1= -0x3f3f3f,ans2=-0x3f3f3f; if(l<=mid) ans1=query_tree1(n<<1,l,r); if(r>mid) ans2=query_tree1(n<<1|1,l,r); return max(ans1,ans2); } int query_tree2(int n,int l,int r){ if(tree[n].l>=l&&tree[n].r<=r){ return tree[n].Mi; } pushdown(n); ll mid=(tree[n].l+tree[n].r)/2; ll ans1= 0x3f3f3f,ans2=0x3f3f3f; if(l<=mid) ans1=query_tree2(n<<1,l,r); if(r>mid) ans2=query_tree2(n<<1|1,l,r); return min(ans1,ans2); } int main(){ int t; cin>>t; while(t--){ int n,m; string s; cin>>n>>m; getchar(); cin>>s; int l=2;int p=0; a[1]=0; for(int i=0; i<s.size(); i++){ if(s[i]=='-'){ p--; a[l]=p; l++; } else if(s[i]=='+'){ p++; a[l]=p; l++; } } build_tree(1,1,n+1); while(m--){ int l,r; cin>>l>>r; l++,r++; int ll=l-1; int rr=r+1; int Ma1=query_tree1(1,1,ll); int Mi1=query_tree2(1,1,ll); int Ma2=query_tree1(1,rr,n+1); int Mi2=query_tree2(1,rr,n+1); int tp=a[r]-a[l-1]; Ma2-=tp; Mi2-=tp; // cout<<Ma2<<" "<<Mi2<<endl; int Max=max(Ma2,Ma1); int Min=min(Mi1,Mi2); cout<<abs(Max-Min)+1<<endl; } } }