[BZOJ4964]加长的咒语
题目大意:
给你一个括号序列s,不一定合法。
有q组询问,每次询问一段区间中最长的合法括号序列的长度。
思路:
首先我们可以将'('看做-1,将')'看做+1,那么我们可以求出这个括号序列的前缀和。
这是一个常用的套路,不难发现对于其中一个合法的子串,其左右两端所对应的前缀和是一样的(然而反之则不一定)。
我们不妨再预处理出每一个括号往左、往右分别能扩展到的最大距离。
对于每一组询问,我们可以找出前缀和最大值max,显然一个合法的括号序列要么与max无关,要么刚好两端都是max。
我们可以求出max再区间内出现的最左和最右的位置l和r,那么答案要么就是[l,r]要么就是[l,m)或(r,m]中最长的合法序列。
这时候我们就可以对于两个区间分别求一下往左、往右能扩展的最大距离,将其作为答案即可。
1 #include<stack> 2 #include<cstdio> 3 #include<cctype> 4 #include<vector> 5 #include<algorithm> 6 inline int getint() { 7 register char ch; 8 while(!isdigit(ch=getchar())); 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const int inf=0x7fffffff,_inf=-0x80000000; 14 const int N=400001; 15 char s[N]; 16 int sum[N],left[N],right[N]; 17 std::stack<int> stack; 18 std::vector<std::pair<int,int> > v; 19 struct SegmentTree { 20 #define _left <<1 21 #define _right <<1|1 22 int sum[N<<2],left[N<<2],right[N<<2]; 23 void push_up(const int &p) { 24 sum[p]=std::max(sum[p _left],sum[p _right]); 25 left[p]=std::max(left[p _left],left[p _right]); 26 right[p]=std::max(right[p _left],right[p _right]); 27 } 28 void build(const int &p,const int &b,const int &e) { 29 if(b==e) { 30 sum[p]=::sum[b]; 31 left[p]=::left[b]; 32 right[p]=::right[b]; 33 return; 34 } 35 const int mid=(b+e)>>1; 36 build(p _left,b,mid); 37 build(p _right,mid+1,e); 38 push_up(p); 39 } 40 int query(const int &p,const int &b,const int &e,const int &l,const int &r,const int val[]) const { 41 if(b==l&&e==r) { 42 return val[p]; 43 } 44 const int mid=(b+e)>>1; 45 int ans=_inf; 46 if(l<=mid) ans=std::max(ans,query(p _left,b,mid,l,std::min(mid,r),val)); 47 if(r>mid) ans=std::max(ans,query(p _right,mid+1,e,std::max(mid+1,l),r,val)); 48 return ans; 49 } 50 #undef _left 51 #undef _right 52 }; 53 SegmentTree t; 54 int main() { 55 const int n=getint(),q=getint(); 56 scanf("%s",&s[1]); 57 v.push_back(std::make_pair(0,0)); 58 for(register int i=1;i<=n;i++) { 59 if(s[i]=='(') sum[i]=sum[i-1]-1; 60 if(s[i]==')') sum[i]=sum[i-1]+1; 61 v.push_back(std::make_pair(sum[i],i)); 62 } 63 std::sort(v.begin(),v.end()); 64 stack.push(0); 65 for(register int i=1;i<=n;i++) { 66 while(stack.size()>1&&sum[stack.top()]<=sum[i]) stack.pop(); 67 left[i]=i-std::upper_bound(v.begin(),v.end(),std::make_pair(sum[i],stack.top()))->second; 68 stack.push(i); 69 } 70 while(!stack.empty()) stack.pop(); 71 stack.push(n); 72 for(register int i=n-1;~i;i--) { 73 while(stack.size()>1&&sum[stack.top()]<=sum[i]) stack.pop(); 74 right[i]=(std::lower_bound(v.begin(),v.end(),std::make_pair(sum[i],stack.top()))-1)->second-i; 75 stack.push(i); 76 } 77 t.build(1,0,n); 78 for(register int i=0;i<q;i++) { 79 const int b=getint()-1,e=getint(); 80 const int max=t.query(1,0,n,b,e,t.sum); 81 const int l=std::lower_bound(v.begin(),v.end(),std::make_pair(max,b))->second; 82 const int r=(std::upper_bound(v.begin(),v.end(),std::make_pair(max,e))-1)->second; 83 int ans=r-l; 84 if(b<l) ans=std::max(ans,t.query(1,0,n,b,l-1,t.right)); 85 if(r<e) ans=std::max(ans,t.query(1,0,n,r+1,e,t.left)); 86 printf("%d\n",ans); 87 } 88 return 0; 89 }