CF380C Sereja and Brackets (线段树)

CF380C Sereja and Brackets

Mean

给定一个括号串\(S\)\(|S|<=10^6\)\(m\)次询问,每次询问区间\([l,r]\)内最长的合法括号串子序列,输出长度。

Sol

线段树。

注意到题目要求的是子序列。

发现去掉合法子序列后,剩余部分字符串表现为\(...)))((((...\)

套路第一次见,直接讲做法。

考虑线段树自底向上区间合并信息,每个节点维护未匹配的左括号数\(lsum\),未匹配的右括号数\(rsum\)

那么两个节点合并向上合并时有如下式子

\(tr[rt].lsum = tr[rt<<1].lsum+tr[rt<<1|1].lsum-min(tr[rt<<1].lsum,tr[rt<<1|1].rsum);\)
\(tr[rt].rsum = tr[rt<<1].rsum+tr[rt<<1|1].rsum-min(tr[rt<<1].lsum,tr[rt<<1|1].rsum);\)

用图形来理解的话,左节点\(..)))(((...\),和右节点\(...)))((((...\)合并,左边的未匹配左括号会和右边的未匹配右括号匹配,数目少的会被全部匹配掉。

最后在查询时采用同样的合并操作,则可以得到查询区间\([L,R]\)内的未匹配右括号数\(rsum\),与未匹配左括号数\(lsum\)。最后答案即为\(ans=(R-L+1)-lsum-rsum\)

Code

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define lowbit(x) (x&(-x))
#define debug(x) cout<<#x<<" :"<<x<<endl
#define debug1(x) cout<<#x<<" :"<<x<<" "
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int N=1e6+20;
const int MAX=10000007;
inline int read() {
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0',c=getchar();}
    return x*f;
}
char s[N];
/**
 * 区间最长合法括号子序列
 * @param x [description]
 */
inline void out(int x) {   
    if(x>9) out(x/10);   
    putchar(x%10+'0'); 
}     
int q[N];
struct node{
    int lsum;//未匹配的左括号数量
    int rsum;//未匹配的右括号数量
}tr[N<<2];

#define mid ((l+r)>>1)
void pushup(int rt){
    tr[rt].lsum = tr[rt<<1].lsum+tr[rt<<1|1].lsum-min(tr[rt<<1].lsum,tr[rt<<1|1].rsum);
    tr[rt].rsum = tr[rt<<1].rsum+tr[rt<<1|1].rsum-min(tr[rt<<1].lsum,tr[rt<<1|1].rsum);
}
void build(int l,int r,int rt){
    if(l==r)
    {
        if(s[l]=='(')tr[rt].lsum+=1;
        else tr[rt].rsum+=1;
        return ;
    }
    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 tr[rt];
    }
    node ls,rs,ans;
    ls = (node){0,0};
    rs = (node){0,0};
    ans = (node){0,0};
    if(L<=mid)ls=query(L,R,l,mid,rt<<1);
    if(R>mid)rs=query(L,R,mid+1,r,rt<<1|1);
    ans.lsum = ls.lsum+rs.lsum-min(ls.lsum,rs.rsum);
    ans.rsum = ls.rsum+rs.rsum-min(ls.lsum,rs.rsum);
    return ans;
}
int t;

int main(){
    scanf("%s",s+1);
    int lens=strlen(s+1);
    build(1,lens,1);
    scanf("%d",&t);
    while(t--){
        int l,r;
        scanf("%d%d",&l,&r);
        node ans = query(l,r,1,lens,1);
        printf("%d\n",r-l+1-ans.lsum-ans.rsum);
    }
    return 0;
}             

posted @ 2021-09-30 11:08  Qquun  阅读(65)  评论(0)    收藏  举报