CF556(div.2) E. Tree Generator

题目大意

以长度为 2 ∗ ( n − 1 ) 2*(n-1) 2(n1)的括号的形式给出一棵 n ( 3 ≤ n ≤ 100000 ) n(3\le n\le 100000) n(3n100000)个节点的有根树,初始位置在根节点处,从左向右遍历括号序列,其中左括号表示派生出一个新的儿子向下走,右括号表示回溯到父亲节点,即向上走。给出 q ( 1 ≤ q ≤ 100000 ) q(1\le q \le 100000) q(1q100000)个操作,每个操作交换序列中两个括号,保证交换后仍然可以表示一颗有根树。对于每一次操作,输出这棵有根树的直径。

题解

假设 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;
}

你可能感兴趣的:(CF)