Codeforces Round #223 (Div. 2): E. Sereja and Brackets(线段树)
题意:
给你一个括号序列和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;
}