【cf1473d Program】 线段树区间查询

题意

我们有一个x,初始为0,我们按字符串顺序进行“+1”或“-1”操作。有m个询问,每次询问我们删去字符串的l到r的符号后,x在完成所有操作中出现的不同数值的总数(包括初始的0)。

思路

因为每次只能进行+-1,所以从a到b必然会经过a到b所有的整数。我们可以用线段树记录下区间的最大和最小值,然后查询删去中间后分开的前面和后面两个部分。后面的部分可以减去经过第r个操作的x和第l个操作之前的x的差。之后就可以通过这两个范围来得出结果。

AC代码

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <functional>
using namespace std;

typedef long long ll;

const int MAXN = 200005;
const int INF = 1e9+7;

typedef struct tree{
    int tmax;
    int tmin;
} tree;

tree stree[MAXN << 2]; //线段树
int num[MAXN]; //原数组

void stree_push_up(int k){ //向上更新
    stree[k].tmax = max(stree[k << 1].tmax, stree[k << 1 | 1].tmax);
    stree[k].tmin = min(stree[k << 1].tmin, stree[k << 1 | 1].tmin);
}

void stree_build(int k,int l,int r){ //建树
    if(l==r){
        stree[k].tmax = num[l]; stree[k].tmin = num[l];
    }
    else{
        int mid = l + ((r - l) >> 1);
        stree_build(k << 1, l, mid);
        stree_build(k << 1 | 1, mid + 1, r);
        stree_push_up(k);
    }
}

tree stree_query(int a,int b,int k,int l,int r){ //区间查询
    if(a<=l&&b>=r) return stree[k];
    int mid = l + ((r - l) >> 1);
    tree res;
    res.tmax = -INF; res.tmin = INF;
    if(a<=mid){
        tree tmp = stree_query(a, b, k << 1, l, mid);
        res.tmax = max(tmp.tmax, res.tmax);
        res.tmin = min(tmp.tmin, res.tmin);
    }
    if(b>mid){
        tree tmp = stree_query(a, b, k << 1 | 1, mid + 1, r);
        res.tmax = max(tmp.tmax, res.tmax);
        res.tmin = min(tmp.tmin, res.tmin);
    }
    return res;
}

char c[MAXN];

int main(){
    int t;
    scanf("%d", &t);
    while(t--){
        int n, m;
        scanf("%d %d",&n,&m);
        getchar();
        scanf("%s", c);
        int x = 0;
        num[1] = 0;
        for (int i = 2; i <= n+1;i++){
            if(c[i-2]=='+') x++;
            else x--;
            num[i] = x;
        }
        stree_build(1, 1, n+1);
        while(m--){
            int a, b;
            scanf("%d %d", &a, &b);
            tree f = stree_query(1, a, 1, 1, n + 1);
            if(b+2<=n+1){
                tree q = stree_query(b+2, n+1, 1, 1, n + 1);
                q.tmax += num[a] - num[b + 1];
                q.tmin += num[a] - num[b + 1];
                f.tmax = max(f.tmax, q.tmax);
                f.tmin = min(f.tmin, q.tmin);
            }
            int sum = f.tmax - f.tmin + 1;
            printf("%d\n", sum);
        }
    }
    return 0;
}
posted @ 2021-01-17 18:24  樱与梅子  阅读(96)  评论(0)    收藏  举报