解法 # 首先,我们需要知道几点正确匹配的括号序列的性质: 如果我们把左括号换成 1,把右括号换成 -1 的话: 序列的和为 0 任意前缀和不小于 0 前缀和中最大值就是嵌套最多的括号数 根据这些性质,我们需要一个可以支持区间修改和查询最值的数据结构,很明显,就是线段树了。 注意:整个序列的和可以通过查询最后一个元素的值来得到,query 函数就是为了干这个的。 Code # #include <bits/stdc++.h> #define forn(i, n) for (int i = 0; i < (int)(n); ++i) #define for1(i, n) for (int i = 1; i <= (int)(n); ++i) #define fore(i, l, r) for (int i = (int)(l); i <= (int)(r); ++i) #define ford(i, n) for (int i = (int)(n)-1; i >= 0; --i) #define pb push_back #define ms(a, x) memset(a, x, sizeof(a)) #define F first #define S second #define endl '\n' #define tr t[root] using namespace std; const int INF = 0x3f3f3f3f; typedef long long ll; typedef pair<int, int> pii; const int N=1e6; int n; struct segt{ int l,r; ll min,max,tag; }t[N<<2]; void build(int root,int l,int r){ t[root].l=l; t[root].r=r; if(l==r) return; int mid=(l+r)>>1; build(root<<1,l,mid); build(root<<1|1,mid+1,r); } void addtag(int p,int x){ t[p].max+=x; t[p].min+=x; t[p].tag+=x; } void spread(int p){ if(t[p].tag){ addtag(p<<1|1,t[p].tag); addtag(p<<1,t[p].tag); t[p].tag=0; } } void update(int root,int l,int r,int x){ if(l<=t[root].l&&r>=t[root].r){ addtag(root,x); return; } spread(root); int mid=(t[root].l+t[root].r)>>1; if(l<=mid) update(root<<1,l,r,x); if(r>mid) update(root<<1|1,l,r,x); tr.max=max(t[root<<1].max,t[root<<1|1].max); tr.min=min(t[root<<1].min,t[root<<1|1].min); } int query(int root,int x){ if(tr.l==tr.r) return tr.max; spread(root); int mid=(tr.l+tr.r)>>1; if(mid>=x) return query(root<<1,x); else return query(root<<1|1,x); } int main() { ios::sync_with_stdio(false); cin.tie(0); cin>>n; int pos=1; vector<int> a(n+1); build(1,1,n); for1(i,n){ char ch; cin>>ch; int val=0; if(ch=='L'){ pos=max(1,pos-1); goto write; }else if(ch=='R'){ pos++; goto write; }else if(ch=='(') val=1; else if (ch==')') val=-1; update(1,pos,n,val-a[pos]); a[pos]=val; write: if(t[1].min<0||query(1,n)!=0) cout<<-1<<' '; else cout<<t[1].max<<' '; } return 0; }