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;
    }
    }
}
View Code
原文地址:https://www.cnblogs.com/sszywq/p/14300264.html