Educational Codeforces Round 102 (Rated for Div. 2) D. Program

题意:
初始 x x x值为 1 1 1,给定一个长度为 n n n的操作序列, ′ + ′ '+' +表示 x = x + 1 x=x+1 x=x+1 ′ − ′ '-' 表示 x = x − 1 x=x-1 x=x1,再给定 m m m个询问,每次给定两个数 l , r l,r l,r,忽视从第 l l l到第 r r r r − l + 1 r-l+1 rl+1个操作,问剩下的操作中可以得到不同数的个数。
数据范围: 1 ≤ n , m ≤ 2 × 1 0 5 , 1 ≤ l ≤ r ≤ n 1\leq n,m\leq 2\times 10^5,1\leq l\leq r\leq n 1n,m2×105,1lrn

题解:
考虑到这是一个连续操作,所以在一次操作序列中的所有操作,出现的数必然在 [ m i n , m a x ] [min,max] [min,max]之间,所以只需要每次找到区间 m i n min min m a x max max即可,记录一个前缀最大最小和后缀最大最小。

每次删除 [ l , r ] [l,r] [l,r]的操作相当于只操作 [ 1 , l − 1 ] [1,l-1] [1,l1] [ r + 1 , n ] [r+1,n] [r+1,n],那么我们可以 O ( 1 ) O(1) O(1)得到 [ 1 , l − 1 ] [1,l-1] [1,l1]的区间最大和最小, O ( 1 ) O(1) O(1)得到 [ r + 1 , n ] [r+1,n] [r+1,n]的区间最大最小,则得到了该区间由 s [ r ] s[r] s[r]上升的最大 u p up up和下降的最大 d o w n down down,之后再得到其由 a [ l − 1 ] a[l-1] a[l1]上升 u p up up和由 a [ l − 1 ] a[l-1] a[l1]下降 d o w n down down,即得到了真正的不操作 [ l , r ] [l,r] [l,r]序列的后的区间最大最小值。

代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

template<typename T>
inline T Read(){
    
    
    T s = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)) {
    
    if(ch == '-') f = -1; ch = getchar();}
    while(isdigit(ch)) {
    
    s = (s << 3) + (s << 1) + ch - '0'; ch = getchar();}
    return s * f;
}

#define read() Read<int>()
#define readl() Read<long long>()

const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
char s[N];
int a[N];
int pmax[N], pmin[N], smax[N], smin[N];
int n, m, l, r;

void solve() {
    
    
	scanf("%d%d", &n, &m);
	scanf("%s", s + 1);
	
	for(int i = 1, v = 0; i <= n; ++i) {
    
    
		if(s[i] == '+') ++v;
		else --v;
		a[i] = v;
	}
	
	pmax[0] = pmin[0] = 0;
	for(int i = 1; i <= n; ++i) {
    
    
		pmax[i] = max(a[i], pmax[i - 1]);
		pmin[i] = min(a[i], pmin[i - 1]);
	}
	
	smax[n + 1] = -INF, smin[n + 1] = INF;
	for(int i = n; i >= 2; --i) {
    
    
		smax[i] = max(smax[i + 1], a[i]);
		smin[i] = min(smin[i + 1], a[i]);
	}
	
	while(m--) {
    
     
		scanf("%d%d", &l, &r);
		
		int lmax = pmax[l - 1], lmin = pmin[l - 1];
		int rmax = smax[r + 1], rmin = smin[r + 1];
		
		int res = 0;
		if(rmax == -INF) {
    
    
			res = lmax - lmin + 1;
		}
		
		else {
    
    
			int up = rmax - a[r];
			int down = a[r] - rmin;
			int mx = max(lmax, a[l - 1] + up);
			int mn = min(lmin, a[l - 1] - down);
			res = mx - mn + 1;
		}
		
		printf("%d\n", res);
	} 
}

int main()
{
    
    
	int T = 1;
	scanf("%d", &T);
	for(int i = 1; i <= T; ++i) solve();

	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43900869/article/details/112671034
今日推荐