首先给出一个引理
一段序列去掉所有的匹配括号之后,剩下的序列一定组成一条链,且这条链的长度就是剩下序列的长度
可以粗糙地证明一下:
学过了树上莫队的知道:原题中的括号序列可以转化为欧拉序
树上的一条路径可以分成 2 种情况,记 first[x] 为 x 第一次在欧拉序中出现的位置, last[x] 同理,这里默认 first[u] < first[v]
其实上面画几个图感性理解一下就可以了
观察去掉匹配括号后,序列一定是 ))…)(…(( 类似这样的,其中 ( 和 ) 都可以没有
我们考虑把 ( 赋值为 1,) 赋值为 -1
那么路径的长度一定是找到一个点 p,从 p 往后的前缀和 - 从 p 往前的后缀和
从中找到的最大值
这个东西可以用线段树维护一下
想象需要记录那些东西:
前缀的最大相减值,后缀的最大相减值,把 [ l,r ] 填满的最大相减值, 总和,前缀和最大值,后缀和最小值,答案
通过这些值可以进行转移
#include <bits/stdc++.h>
using namespace std;
const int N(200100);
int n,m;
char c[N];
inline int max3(int x,int y,int z){
return max(max(x,y),z);
}
inline int max4(int x,int y,int z,int k){
return max(max(x,y),max(z,k));
}
struct SegmentTree{//维护前缀和数组
struct Node{
int lmax,rmax,fillmax,sum,premx,sufmn,ans;
}seg[N<<2];
void pushup(int x){
seg[x].sum=seg[x<<1].sum+seg[x<<1^1].sum;
seg[x].fillmax=max(seg[x<<1].fillmax+seg[x<<1^1].sum,seg[x<<1^1].fillmax-seg[x<<1].sum);
seg[x].lmax=max3(seg[x<<1].lmax,seg[x<<1].fillmax+seg[x<<1^1].premx,seg[x<<1^1].lmax-seg[x<<1].sum);
seg[x].rmax=max3(seg[x<<1^1].rmax,seg[x<<1^1].fillmax-seg[x<<1].sufmn,seg[x<<1^1].sum+seg[x<<1].rmax);
seg[x].premx=max(seg[x<<1].premx,seg[x<<1].sum+seg[x<<1^1].premx);
seg[x].sufmn=min(seg[x<<1^1].sufmn,seg[x<<1^1].sum+seg[x<<1].sufmn);
seg[x].ans=max4(seg[x<<1].ans,seg[x<<1^1].ans,seg[x<<1].rmax+seg[x<<1^1].premx,seg[x<<1^1].lmax-seg[x<<1].sufmn);
}
void build(int l,int r,int x){
if(l==r){
if(c[l]=='(')
seg[x].lmax=seg[x].rmax=seg[x].fillmax=seg[x].sum=seg[x].premx=seg[x].ans=1,seg[x].sufmn=0;
else
seg[x].sum=seg[x].sufmn=-1,seg[x].fillmax=seg[x].lmax=seg[x].rmax=seg[x].ans=1,seg[x].premx=0;
return;
}
int mid=(l+r)>>1;
build(l,mid,x<<1),build(mid+1,r,x<<1^1);
pushup(x);
// cout<<l<<' '<<r<<" : "<<seg[x].sum<<' '<<seg[x].fillmax<<' '<<seg[x].lmax<<' '<<seg[x].rmax<<' '<<seg[x].premx<<' '<<seg[x].sufmn<<' '<<seg[x].ans<<'\n';
}
void modify(int l,int r,int x,int p,int k){
if(l==r){
if(k==1)
seg[x].lmax=seg[x].rmax=seg[x].fillmax=seg[x].sum=seg[x].premx=seg[x].ans=1,seg[x].sufmn=0;
else
seg[x].sum=seg[x].sufmn=-1,seg[x].fillmax=seg[x].lmax=seg[x].rmax=seg[x].ans=1,seg[x].premx=0;
return;
}
int mid=(l+r)>>1;
if(mid>=p)
modify(l,mid,x<<1,p,k);
else
modify(mid+1,r,x<<1^1,p,k);
pushup(x);
// cout<<l<<' '<<r<<" : "<<seg[x].sum<<' '<<seg[x].fillmax<<' '<<seg[x].lmax<<' '<<seg[x].rmax<<' '<<seg[x].premx<<' '<<seg[x].sufmn<<' '<<seg[x].ans<<'\n';
}
}SGT;
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar())
if(ch=='-')
RR=-1;
for(;isdigit(ch);ch=getchar())
FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
int main(){
n=read(),m=read();n=(n-1)<<1;
scanf("%s",c+1);
SGT.build(1,n,1);
cout<<SGT.seg[1].ans<<'\n';
for(int i=1;i<=m;i++){
int x=read(),y=read();
if(c[x]!=c[y]){
if(c[x]=='(')
SGT.modify(1,n,1,x,-1),SGT.modify(1,n,1,y,1);
else
SGT.modify(1,n,1,x,1),SGT.modify(1,n,1,y,-1);
swap(c[x],c[y]);
}
printf("%d\n",SGT.seg[1].ans);
}
return 0;
}