Codeforces Round #223 (Div. 2): E. Sereja and Brackets(线段树)

版权声明:本文为博主原创文章,你们可以随便转载 https://blog.csdn.net/Jaihk662/article/details/83547664

题意:

给你一个括号序列和m次询问,每次询问区间[L, R]内匹配的括号个数

思路:

这道题线段树只用来维护区间最小值,所以理论上RMQ也可以,主要是要稍微推一下

设左括号为1,右括号为-1,s[]为前缀和

那么区间[L, R]内不匹配的右括号个数就是min(s[L-1…R])-s[L-1]

区间[L, R]内不匹配的左括号个数就是max(S[R]-s[L-1]-(min(s[L-1…R])-s[L-1]), 0)

区间长度减去上面两个就是答案了

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
int n, tre[4000015], a[1000005];
char str[1000005];
void Create(int l, int r, int x)
{
	int m;
	if(l==r)
	{
		tre[x] = a[r];
		return;
	}
	m = (l+r)/2;
	Create(l, m, x*2);
	Create(m+1, r, x*2+1);
	tre[x] = min(tre[x*2], tre[x*2+1]);
}
int Query(int l, int r, int x, int c, int d)
{
	int m, now;
	if(l>=c && r<=d)
		return tre[x];
	m = (l+r)/2;
	now = 1000000;
	if(c<=m)
		now = min(now, Query(l, m, x*2, c, d));
	if(d>=m+1)
		now = min(now, Query(m+1, r, x*2+1, c, d));
	return now;
}
int main(void)
{
	int x, y, T, i, bet;
	scanf("%s%d", str+1, &T);
	n = strlen(str+1);
	for(i=1;i<=n;i++)
		a[i] = a[i-1]+(str[i]=='('?1:-1);
	Create(1, n, 1);
	while(T--)
	{
		scanf("%d%d", &x, &y);
		bet = min(Query(1, n, 1, x, y), a[x-1])-a[x-1];
		printf("%d\n", y-x+1+bet-max(a[y]-a[x-1]-bet, 0));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Jaihk662/article/details/83547664