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

 

posted @ 2017-12-12 20:48  skylee03  阅读(213)  评论(0编辑  收藏  举报