【Codeforces】Codeforces Round #223 (Div. 1) C - Sereja and Brackets

148 阅读2分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

题目链接

Problem - C - Codeforces

题目

Sereja has a bracket sequence s1,s2,...,sns_1,s_2,...,s_n, or, in other words, a string ss of length nn, consisting of characters "(" and ")".

Sereja needs to answer mm queries, each of them is described by two integers li,ri (1lirin)l_i, r_i (1 ≤ l_i* ≤ r_i ≤ n). The answer to the i-th query is the length of the maximum correct bracket subsequence of sequence sli,sli+1,...,sris_{l_i},s_{l_i+1},...,s_{r_i}. Help Sereja answer all queries.

You can find the definitions for a subsequence and a correct bracket sequence in the notes.

Input

The first line contains a sequence of characters s1,s2,...,sns_1,s_2,...,s_n(1n106)(1 ≤ n ≤ 10^6) without any spaces. Each character is either a "(" or a ")". The second line contains integer m (1m105)m (1 ≤ m≤ 10^5) — the number of queries. Each of the next mm lines contains a pair of integers. The i-th line contains integers li,ri (1lirin)l_i, r_i (1 ≤ l_i* ≤ r_i ≤ n) — the description of the i-th query.

Output

Print the answer to each question on a single line. Print the answers in the order they go in the input.

题目大意

给一个仅有左右括号构成的字符串,q 组询问,每组询问需要回答 l 到 r 之间最长的合法括号序列长度。

思路

易知在只有一种括号的情况下,任意时刻前缀左括号数量不超过右括号数量,最终两种括号数量相等即为合法括号序列。所以两个合法的括号序列分别不改变自身顺序的情况下交错插在一起,形成的新括号序列依然合法。

用线段树维护每一段答案、未匹配的左括号的数量、未能匹配的右括号的数量。

合并两段相邻区间的答案时,左边一段中若干个未能匹配的左括号可与右边一段同样数量的未能匹配的右括号组成合法的括号系列,并与左右两段本身具有的合法括号序列按顺序交错相插,最终形成的序列依然合法。所以记左段为 lseq,右段落 rseq,两者合并:

  • 答案=左段的答案+右段的答案+min(左段未匹配的左括号数量,右段未匹配的右括号数量)*2
  • 未匹配的左括号数量=左段的未匹配左括号数量+右段的未匹配左括号数量+min(左段的左括号数量,右段的右括号数量)
  • 未匹配的右括号数量=左段的未匹配右括号数量+右段的未匹配右括号数量+min(左段的左括号数量,右段的右括号数量)

线段树正常建树查询即可。

代码

#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
const int N=1000005;
struct asdf{
	int cntl,cntr,cp;
}s[N<<2],o;
char a[N];
int n;
void build(int l,int r,int rt)
{
	if (l==r)
	{
		if (a[l]=='(') s[rt].cntl++;
		else s[rt].cntr++;
		return;
	}
	build(l,l+r>>1,rt<<1);
	build((l+r>>1)+1,r,rt<<1|1);
	s[rt].cp=s[rt<<1].cp+s[rt<<1|1].cp+min(s[rt<<1].cntl,s[rt<<1|1].cntr)*2;
	s[rt].cntl=s[rt<<1].cntl+s[rt<<1|1].cntl-min(s[rt<<1].cntl,s[rt<<1|1].cntr);
	s[rt].cntr=s[rt<<1].cntr+s[rt<<1|1].cntr-min(s[rt<<1].cntl,s[rt<<1|1].cntr);
        return;
}
asdf getans(int l,int r,int rt,int x,int y)
{
	if (x<=l&&r<=y) return s[rt];
	asdf t,lson=o,rson=o;
	if (x<=(l+r>>1)) lson=getans(l,l+r>>1,rt<<1,x,y);
	if (y>(l+r>>1)) rson=getans((l+r>>1)+1,r,rt<<1|1,x,y);
	t.cp=lson.cp+rson.cp+min(lson.cntl,rson.cntr)*2;
	t.cntl=lson.cntl+rson.cntl-min(lson.cntl,rson.cntr);
	t.cntr=lson.cntr+rson.cntr-min(lson.cntl,rson.cntr);
	return t;
}
int main()
{
	scanf("%s",a+1);
	n=strlen(a+1);
	build(1,n,1);
	int T,x,y;
	for (scanf("%d",&T);T--;)
	{
		scanf("%d%d",&x,&y);
		printf("%d\n",getans(1,n,1,x,y).cp);
	}
        return 0;
}