当前位置 : 主页 > 编程语言 > c++ >

Sereja and Brackets CodeForces - 380C (线段树+分治思路)

来源:互联网 收集:自由互联 发布时间:2021-06-23
Sereja and Brackets 题目链接: CodeForces - 380C Sereja has a bracket sequence s 1,? s 2,?...,?*s**n , or, in other words, a string s* of length n , consisting of characters "(" and ")". Sereja needs to answer m queries, each of them i

Sereja and Brackets

题目链接: CodeForces - 380C

Sereja has a bracket sequence s1,?s2,?...,?*s**n, or, in other words, a string s* of length n, consisting of characters "(" and ")".

Sereja needs to answer m queries, each of them is described by two integers li,?ri(1?≤?li?≤?ri?≤?n). The answer to the i-th query is the length of the maximum correct bracket subsequence of sequence sli,?sli?+?1,?...,?sri. 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,?...,?*s**n* (1?≤?n?≤?106) without any spaces. Each character is either a "(" or a ")". The second line contains integer m (1?≤?m?≤?105) — the number of queries. Each of the next m lines contains a pair of integers. The i-th line contains integers li,?ri (1?≤?li?≤?ri?≤?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.

Examples

Input

())(())(())(71 12 31 21 128 125 112 10

Output

00210466

Note

A subsequence of length |x| of string s?=?s1s2... s|s| (where |s| is the length of string s) is string x?=?sk1sk2... *s**k|x| (1?≤?k1?<?k2?<?...?<?k|x|?≤?|s*|).

A correct bracket sequence is a bracket sequence that can be transformed into a correct aryphmetic expression by inserting characters "1" and "+" between the characters of the string. For example, bracket sequences "()()", "(())" are correct (the resulting expressions "(1)+(1)", "((1+1)+1)"), and ")(" and "(" are not.

For the third query required sequence will be ?()?.

For the fourth query required sequence will be ?()(())(())?.

题意:

给你一个只含有‘(‘ 和‘)‘ 的字符串,

以及q个询问,每一个询问给你两个整数l和r,代表一个区间。对于每一个询问,让你输出区间中能选出最长的子序列是合法的括号序列的长度。

思路:

线段树+分治的思想来解决此问题。

我们线段树每一个区间维护以下信息:

1、区间中能选出最长的子序列是合法的括号序列的个数 num。

2、 区间中多余的‘(‘ 字符的个数 a

3、区间中多余的‘)‘ 字符的个数 b

那么对于区间合并时,

num=左儿子的num+右儿子的num+min(左儿子的a,右儿子的b)

a=左儿子的a+右儿子的a - min(左儿子的a,右儿子的b)

b=左儿子的b+右儿子的b - min(左儿子的a,右儿子的b)

最后输出时,注意num个括号个数,*2才是长度。

细节见代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {ll ans = 1; while (b) {if (b % 2) { ans = ans * a % MOD; } a = a * a % MOD; b /= 2;} return ans;}
inline void getInt(int *p);
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
struct node {
    int l, r;
    int num;
    int a;// (
    int b;// )
} segmeng_tree[maxn << 2];
char s[maxn];
int n;
int m;
void pushup(int rt)
{
    int x = min(segmeng_tree[rt << 1].a, segmeng_tree[rt << 1 | 1].b);
    segmeng_tree[rt].num = x + segmeng_tree[rt << 1].num + segmeng_tree[rt << 1 | 1].num;
    segmeng_tree[rt].a = segmeng_tree[rt << 1].a + segmeng_tree[rt << 1 | 1].a - x;
    segmeng_tree[rt].b = segmeng_tree[rt << 1].b + segmeng_tree[rt << 1 | 1].b - x;
}
void build(int rt, int l, int r)
{
    segmeng_tree[rt].l = l;
    segmeng_tree[rt].r = r;
    if (l == r) {
        segmeng_tree[rt].a = s[l] == '(';
        segmeng_tree[rt].b = s[l] == ')';
        segmeng_tree[rt].num = 0;
    } else {
        int mid = (l + r) >> 1;
        build(rt << 1, l, mid);
        build(rt << 1 | 1, mid + 1, r);
        pushup(rt);
    }
}

node ask(int rt, int l, int r)
{
    if (segmeng_tree[rt].l >= l && segmeng_tree[rt].r <= r) {
        return segmeng_tree[rt];
    }
    int mid = (segmeng_tree[rt].l + segmeng_tree[rt].r) >> 1;
    if (r <= mid) {
        return ask(rt << 1, l, r);
    } else if (l > mid) {
        return ask(rt << 1 | 1, l, r);
    } else {
        node res1 = ask(rt << 1, l, r);
        node res2 = ask(rt << 1 | 1, l, r);
        node res = res1;
        int x = min(res1.a, res2.b);
        res.num += x;
        res.b += res2.b;
        res.a += res2.a;
        res.num += res2.num;
        res.b -= x;
        res.a -= x;
        return res;
    }
}
int main()
{
    //freopen("D:\\code\\text\\input.txt","r",stdin);
    //freopen("D:\\code\\text\\output.txt","w",stdout);
    scanf("%s", s + 1);
    n = strlen(s + 1);
    build(1, 1, n);
    scanf("%d", &m);
    while (m--) {
        int l, r;
        scanf("%d %d", &l, &r);
        printf("%d\n", ask(1, l, r).num * 2);
    }
    return 0;
}

inline void getInt(int *p)
{
    char ch;
    do {
        ch = getchar();
    } while (ch == ' ' || ch == '\n');
    if (ch == '-') {
        *p = -(getchar() - '0');
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 - ch + '0';
        }
    } else {
        *p = ch - '0';
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 + ch - '0';
        }
    }
}
网友评论