Educational Codeforces Round 102 D. Program(线段树)

D. Program

题目传送门:

D. Program

思路:

如果要求过程中最多经过多少个数,那么只要求得 区间最大值 - 区间最小+1 即可。区间的最大值和最小值,我们显然都可以用线段树维护,但是题目中还有一个区间的删除操作该怎么进行呢。
1.如果删除的区间是后半段,那么只要查询前半段区间的最大值和最小值即可
2.如果删除的区间是前半段,那么在查寻后半段区间的最大值和最小值之后,还要将其减去删去区间的和。
3.如果删去的区间位于中间,那么就要同时进行第一步和第二步的判断。
但需要注意的是,不管是哪种情况,你都得考虑最大值,最小值和0的关系,因为最开始为0。

AC Code

/*
1.删前半段,那么要查询后半段的最大值和最小值
2.删狐半段,那么要查询前半段的最大值和最小值
3.删中间,那么要同时查询前半段和后半段,并且大的取大,小的取小
需要注意的是,不管是哪种情况,都需要注意和0的关系
*/
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N],sum[N];
struct node
{
    
    
    int k,l,r;
    int minn,maxn;
}tr[N*4];
void pushup(int k)
{
    
    
    tr[k].maxn=max(tr[k<<1].maxn,tr[k<<1|1].maxn);
    tr[k].minn=min(tr[k<<1].minn,tr[k<<1|1].minn);
}
void build(int k,int l,int r)//建树
{
    
    
    tr[k].l=l,tr[k].r=r;
    if(l==r)
    {
    
    
        tr[k].maxn=tr[k].minn=sum[l];
        return ;
    }
    int mid=(l+r)/2;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    pushup(k);
}
int query_min(int k,int l,int r)//查询区间最小值
{
    
    
    if(tr[k].l>=l&&tr[k].r<=r)
        return tr[k].minn;
    int mid=(tr[k].l+tr[k].r)/2;
    int ans=4e5;
    if(l<=mid) ans=query_min(k<<1,l,r);
    if(r>mid) ans=min(ans,query_min(k<<1|1,l,r));
    return ans;  
}
int query_max(int k,int l,int r)//查询区间最大值
{
    
    
    if(tr[k].l>=l&&tr[k].r<=r)
        return tr[k].maxn;
    int mid=(tr[k].l+tr[k].r)/2;
    int ans=-4e5;
    if(l<=mid) ans=query_max(k<<1,l,r);
    if(r>mid) ans=max(ans,query_max(k<<1|1,l,r));
    return ans; 
}
int main()
{
    
    
    int t;
    scanf("%d",&t);
    while(t--)
    {
    
    
        int n,m;
        scanf("%d%d",&n,&m);
        string str;
        cin>>str;
        for(int i=0;i<n;i++)
        {
    
    
            if(str[i]=='-') a[i+1]=-1;
            else a[i+1]=1;
        }
        for(int i=1;i<=n;i++)
            sum[i]=sum[i-1]+a[i];
        build(1,1,n);
        while(m--)
        {
    
    
            int x,y;
            int res;
            scanf("%d%d",&x,&y);
            if(x==1&&y==n) printf("1\n");
            else if(x==1)   //删去前半段
            {
    
    
                int maxn=query_max(1,y+1,n);
                int minn=query_min(1,y+1,n);
                maxn=maxn-sum[y];
                minn=minn-sum[y];
                res=maxn-minn+1;
                if(minn>0||maxn<0) res++;
                printf("%d\n",res);
            }
            else if(y==n)   //删去后半段
            {
    
    
                int maxn=query_max(1,1,x-1);
                int minn=query_min(1,1,x-1);
                res=maxn-minn+1;
                if(minn>0||maxn<0) res++;
                printf("%d\n",res);
            }
            else    //删去中间
            {
    
    
                int maxn1=query_max(1,1,x-1);
                int minn1=query_min(1,1,x-1);
                int maxn2=query_max(1,y+1,n);
                int minn2=query_min(1,y+1,n);
                maxn2=maxn2-(sum[y]-sum[x-1]);
                minn2=minn2-(sum[y]-sum[x-1]);
                int maxn=max(maxn1,maxn2);
                int minn=min(minn1,minn2);
                res=maxn-minn+1;
                if(minn>0||maxn<0) res++;
                printf("%d\n",res);
            }
        }   
    }
    //system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Stevenwuxu/article/details/112932624
今日推荐