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;
}

浙公网安备 33010602011771号