codeforces 380C 线段树括号匹配

Sereja and Brackets

Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d
& %I64u

Submit Status

Description

Sereja has a bracket sequence s1,?s2,?...,?sn, 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,?...,?sn(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.

Sample Input

Input

())(())(())(
7
1 1
2 3
1 2
1 12
8 12
5 11
2 10

Output

0
0
2
10
4
6
6

Hint

A subsequence of length |x| of string s?=?s1s2... s|s| (where |s| is
the length of string s) is string x?=?sk1sk2... sk|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 ?()(())(())?.

给出一段序列,问在这段序列中有几对完整的括号匹配

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 1111111
using namespace std;
struct Node
{
    int l,r,all;
    Node()
    {
        l=r=all=0;
    }
    Node(int a,int b,int c)
    {
        l=a,r=b,all=c;
    }
};
Node sum[MAXN<<2];
char str[MAXN];
void pushup(int rt)
{
    int t=min(sum[rt<<1].l,sum[rt<<1|1].r);
    sum[rt].all=sum[rt<<1].all+sum[rt<<1|1].all+t;
    sum[rt].l=sum[rt<<1].l+sum[rt<<1|1].l-t;
    sum[rt].r=sum[rt<<1].r+sum[rt<<1|1].r-t;
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        if(str[l]=='(')
            sum[rt].l++;
        else if(str[l]==')')
            sum[rt].r++;
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}
Node query(int l,int r,int L,int R,int rt)
{
    if(l>=L&&R>=r)
        return sum[rt];
    Node cnt1,cnt2;
    int mid=(l+r)>>1;
    if(L<=mid)
        cnt1=query(l,mid,L,R,rt<<1);
    if(R>mid)
        cnt2=query(mid+1,r,L,R,rt<<1|1);
    int t=min(cnt1.l,cnt2.r);
    return Node(cnt1.l+cnt2.l-t,cnt1.r+cnt2.r-t,cnt1.all+cnt2.all+t);
}
int main()
{
    int q,l,r;
    scanf("%s",str+1);
    scanf("%d",&q);
    int n=strlen(str+1);
    build(1,n,1);
    while(q--)
    {
        scanf("%d %d",&l,&r);
        printf("%d\n",2*query(1,n,l,r,1).all);
    }
    return 0;
}
时间: 2024-07-29 05:17:03

codeforces 380C 线段树括号匹配的相关文章

Codeforces 384E 线段树+dfs序

题目链接:点击打开链接 题意: 给定n个点,m个询问的无向树(1为根) 下面n个数表示每个点的权值 下面n-1行给出树 操作1:x点权值+v, x的第 i & 1 的儿子-v, 第 !(i&1) 的儿子+v 操作2:询问x点权值 dfs把树转成序列 根据深度把点分成2组 分别用线段树维护.. 然后Y一下 #include<stdio.h> #include<string.h> #include<iostream> #include<algorith

Codeforces 446C 线段树 递推Fibonacci公式

聪哥推荐的题目 区间修改和区间查询,但是此题新颖之处就在于他的区间修改不是个定值,而是从L 到 R 分别加 F1.F2....Fr-l+1 (F为斐波那契数列) 想了一下之后,觉得用fib的前缀和来解决,每次做懒惰标记记录下当前区间是从哪个L开始加起的,敲了一半之后发现有问题,就跟上次遇到的懒惰标记问题一样,这是个覆盖性的懒惰标记,每次向下传递后,都要先清除孩子的,清除孩子的也有可能要清除son's son,所以要一直pushdown下去,否则就会错,但这样就会超时. 能不能有个累加型的标记让我

Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论

Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论 题意 给你一段数,然后小明去猜某一区间内的gcd,这里不一定是准确值,如果在这个区间内改变一个数的值(注意不是真的改变),使得这个区间的gcd是小明所猜的数也算小明猜对.另一种操作就是真的修改某一点的值. 解题思路 这里我们使用线段树,维护区间内的gcd,判断的时候需要判断这个区间的左右子区间的gcd是不是小明猜的数的倍数或者就是小明猜的数,如果是,那么小明猜对了.否则就需要进入这个区间

Codeforces 833B 线段树优化 dp

Codeforces  833B  The Bakery 题意: n 个数要分成 k 块,每块的价值是其不同数的个数,问价值和最大是多少. tags: dp[i][j]表示前 j 个数分成 i 块的最大权值和,转移: dp[i][j] = max( dp[i-1][k] + val[k+1][j] ) , k是 1~j . 但这个过程其实并不好转移,要利用累加的特点,用线段树进行优化 (感觉我不看题解是想不到的,2333) 大概就是,对于第 i 层,我们假定已经知道了第 i-1 层,也就是求出了

Vijos1448题解---线段树+括号法

描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:K=1,K=1,读入l.r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同K=2,读入l,r表示询问l~r之间能见到多少种树(l,r>0) 输入格式 第一行n,m表示道路总长为n,共有m个操作接下来m行为m个操作 输出格式 对于每个k=2输出一个答案 样例输入 5 4 1 1 3 2 2 5 1 2 4 2 3 5

codeforces 997E(线段树)

分析: 首先考虑如何计算整个数组有多少个good区间 容易发现一个区间是good区间当且仅当max-min-len=-1,且任意区间max-min-len>=-1 我们可以枚举右端点,然后维护前面每个位置到当前右端点的max-min-len值,容易发现我们只需要维护区间最小值和最小值的个数就行了,于是用线段树即可 于是我们可以得到以某个点为右端点的时候合法区间总数,那么我们把每次的结果加起来,就得到了整个数组有多少个good区间 每次右端点移动怎么更新呢?显然我们只需要用一个max单调栈,一个m

Codeforces 938G 线段树分治 线性基 可撤销并查集

Codeforces 938G Shortest Path Queries 一张连通图,三种操作 1.给x和y之间加上边权为d的边,保证不会产生重边 2.删除x和y之间的边,保证此边之前存在 3.询问x到y的路径异或最小值 保证图在任意时刻连通 首先连通图路径异或相当于从x到y的任意一条路径再异或上若干个环得到的,只要在dfs过程中把非树边成的环丢到线性基里就好了,其他环一定可以通过这些环异或组合出来 有加边删边操作怎么做呢?线段树时间分治!注意到不能保证在线段树的任意一个节点图是连通的,需要用

codeforces 589G:线段树+二分

离线做 先按照t[]建线段树,维护区间的有效天数以及可用时间 然后把t[]从小到达排序,记得记录t中元素在线段树中的位置 把询问按照d从小到大排序,依次考虑 由于按照d排序,所以当前询问肯定是d最短的,我们在t数组中找到大于当前d的第一个元素位置,把这之前的元素全部从线段树中删除,表示这些天数无效 因为当前d已经是最小,所以删除对后续不会有影响 二分一个天数,查找0~mid天一共的工作时间(工作时间=总可用时间-准备时间*有效天数) #include"cstdio" #include&

CodeForces 343D 线段树维护dfs序

给定一棵树,初始时树为空 操作1,往某个结点注水,那么该结点的子树都注满了水 操作2,将某个结点的水放空,那么该结点的父亲的水也就放空了 操作3,询问某个点是否有水 我们将树进行dfs, 生成in[u], 访问结点u的时间戳,out[u],离开结点u的时间戳 每个结点的in值对应在线段树中的区间的一点 那么对于操作1, 只要将区间[in[u],out[u]] 的值都改为1, 但是如果区间[in[u],out[u]] 原先存在为0的点,那么父区间肯定是空的,这个操作不能 改变父区间的状态,所以需要