以长度为 2 ∗ ( n − 1 ) 2*(n-1) 2∗(n−1)的括号的形式给出一棵 n ( 3 ≤ n ≤ 100000 ) n(3\le n\le 100000) n(3≤n≤100000)个节点的有根树,初始位置在根节点处,从左向右遍历括号序列,其中左括号表示派生出一个新的儿子向下走,右括号表示回溯到父亲节点,即向上走。给出 q ( 1 ≤ q ≤ 100000 ) q(1\le q \le 100000) q(1≤q≤100000)个操作,每个操作交换序列中两个括号,保证交换后仍然可以表示一颗有根树。对于每一次操作,输出这棵有根树的直径。
假设 h ( u ) h(u) h(u)表示 u u u的深度, d ( u , v ) d(u,v) d(u,v)表示 u u u到 v v v的距离,那么 d ( u , v ) = h ( u ) + h ( v ) − 2 h ( l c a ( u , v ) ) d(u,v)=h(u)+h(v)-2h(lca(u,v)) d(u,v)=h(u)+h(v)−2h(lca(u,v)),直径就是 d ( u , v ) d(u,v) d(u,v)的最大值,所以我们要维护等式右端的所有东西,即 h ( a ) h(a) h(a)的最大值、 h ( a ) − 2 h ( b ) h(a)-2h(b) h(a)−2h(b)的最大值、 − 2 h ( b ) -2h(b) −2h(b)的最大值、 − 2 h ( b ) + h ( c ) -2h(b)+h(c) −2h(b)+h(c)的最大值、 h ( a ) − 2 h ( b ) + h ( c ) h(a)-2h(b)+h(c) h(a)−2h(b)+h(c)的最大值。维护的方法就是线段树,线段树上每个节点代表一段括号子序列,除了维护上面五个值,还需要维护一个这段括号序列的深度,注意,这里的深度是可以为负数的,比如说某个叶子节点只有一个右括号,那么深度就为 − 1 -1 −1。代码写起来不麻烦,关键就是合并时要多注意一下。
#include
#define lson u<<1,l,mid
#define rson u<<1|1,mid+1,r
using namespace std;
int n,q;
char s[200005];
struct SEGMENTTREE{
int d,mx1,mx2,mx3,mx4,mx5;
}t[200005<<2];
void maintain(int u){
t[u].d=t[u<<1].d+t[u<<1|1].d;
t[u].mx1=max(t[u<<1].mx1,t[u<<1].d+t[u<<1|1].mx1);
t[u].mx2=max(t[u<<1].mx2,-2*t[u<<1].d+t[u<<1|1].mx2);
t[u].mx3=max(max(t[u<<1].mx3,-t[u<<1].d+t[u<<1|1].mx3),t[u<<1].mx1-2*t[u<<1].d+t[u<<1|1].mx2);
t[u].mx4=max(max(t[u<<1].mx4,-t[u<<1].d+t[u<<1|1].mx4),t[u<<1].mx2+t[u<<1].d+t[u<<1|1].mx1);
t[u].mx5=max(max(t[u<<1].mx5,t[u<<1|1].mx5),
max(t[u<<1].mx1-t[u<<1].d+t[u<<1|1].mx4,t[u<<1].mx3+t[u<<1].d+t[u<<1|1].mx1));
}
void se(int u,int x){
if(s[x]=='('){
t[u]=(SEGMENTTREE){1,1,0,0,1,1};
}else{
t[u]=(SEGMENTTREE){-1,0,2,2,1,1};
}
}
void build(int u,int l,int r){
if(l==r){
se(u,l);
return;
}
int mid=(l+r)>>1;
build(lson);build(rson);
maintain(u);
}
void update(int u,int l,int r,int x){
if(l==r){
if(s[x]=='(')s[x]=')';
else s[x]='(';
se(u,x);
return;
}
int mid=(l+r)>>1;
if(x<=mid)update(lson,x);
else update(rson,x);
maintain(u);
}
int main(){
scanf("%d%d%s",&n,&q,s+1);
build(1,1,2*(n-1));
printf("%d\n",t[1].mx5);
for(int x,y,i=1;i<=q;i++){
scanf("%d%d",&x,&y);
update(1,1,2*(n-1),x);
update(1,1,2*(n-1),y);
printf("%d\n",t[1].mx5);
}
return 0;
}