CF1149C Tree Generator™——普通线段树

题目

传送门

题解

解决这道题分两步走:

第一步,把问题转化一下。题面里详细地讲了括号树的定义(就是图片上边那一坨英文),这个就不用我补充了吧;

既然树的直径的定义是树上最长的一条路径,也就是距离最远的两点间的距离,想想在括号树里边两点的距离是什么,我们发现就是两点间的剩余括号数量(即除去匹配成功的括号),不信你可以看看样例,为什么呢?因为括号序列其实就是欧拉序

现在我们要求距离最远的两点的距离,也就是找括号序列上所有点对构成的区间中剩余括号数量的最大值S,而除了点对构成的区间外,其它区间的剩余括号数量不可能超过S,所以我们最后把问题转化成:带修改,求所有区间中剩余括号数量的最大值,显然的线段树。

第二步,考虑怎么写。因为线段树上一个区间中的最大剩余括号序列要么在左区间,要么在右区间,要么覆盖左右两边各一部分,所以每个结点要维护最大值、前缀、后缀等的信息,然后由于剩余括号序列必定是几个连续的右括号跟几个连续的左括号,所以又要维护每个答案的前缀右括号、后缀左括号,为了协助计算,还得维护区间剩余括号序列前缀、后缀,......,所以最后我写出了这么个合并操作(仅合并部分):

(然后)

。。

。。。

最后正是印证了那句歌词:“两百行10kb代码,运行后错误在哪~”

有没有更好写的做法呢?有!

当你把两个剩余括号序列合并起来时,设前一个的右括号数为a,左括号数为b,后一个的右括号数为c,左括号数为d,合并后序列长度为a+abs(c-b)+d=max(a+b+d-c,a-b+d+c),此时把max拆开来,发现每个区间只需要维护后缀右括号a+后缀左括号b、后缀右括号a-后缀左括号b、前缀左括号d+前缀右括号c、前缀左括号d-前缀右括号c这4个量的最大值以及答案即可;

要维护这4个值,还需要用到两个辅助,整个区间构成的剩余括号序列的右括号、左括号数e、f。显然,我们可以手推出下列式子:

//"ab"即a+b,"a_b"即a-b
t[x].ab=max(t[x<<1|1].ab,max(t[x<<1].ab-t[x<<1|1].e+t[x<<1|1].f,t[x<<1].a_b+t[x<<1|1].e+t[x<<1|1].f));
t[x].a_b=max(t[x<<1|1].a_b,t[x<<1].a_b+t[x<<1|1].e-t[x<<1|1].f);

也就是说,a+b、a-b并不需要记录a和b的值来维护(而且光用a和b的值维护也无法保证正确性),d+c、d-c同理,

于是可以得到如下清爽的合并操作:

inline void docnt(int x){
	t[x].ab=max(t[x<<1|1].ab,max(t[x<<1].ab-t[x<<1|1].e+t[x<<1|1].f,t[x<<1].a_b+t[x<<1|1].e+t[x<<1|1].f));
	t[x].a_b=max(t[x<<1|1].a_b,t[x<<1].a_b+t[x<<1|1].e-t[x<<1|1].f);
	t[x].dc=max(t[x<<1].dc,max(t[x<<1|1].dc-t[x<<1].f+t[x<<1].e,t[x<<1|1].d_c+t[x<<1].f+t[x<<1].e));
	t[x].d_c=max(t[x<<1].d_c,t[x<<1|1].d_c+t[x<<1].f-t[x<<1].e);
	t[x].s=max(t[x<<1].ab+t[x<<1|1].d_c,t[x<<1].a_b+t[x<<1|1].dc);
	t[x].s=max(t[x].s,max(t[x<<1].s,t[x<<1|1].s));
	t[x].e=t[x<<1].e+max(0,t[x<<1|1].e-t[x<<1].f);
	t[x].f=t[x<<1|1].f+max(0,t[x<<1].f-t[x<<1|1].e);
}

剩下就是普通线段树了。。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define ll long long
#define MAXN 200005
using namespace std;
inline ll read(){
	ll x=0;bool f=1;char s=getchar();
	while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
	while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+s-'0',s=getchar();
	return f?x:-x;
}
int n,m,R;
struct itn{
	int ab,a_b,dc,d_c,s,e,f;
}t[MAXN<<2];
char s[MAXN];
inline void docnt(int x){
	t[x].ab=max(t[x<<1|1].ab,max(t[x<<1].ab-t[x<<1|1].e+t[x<<1|1].f,t[x<<1].a_b+t[x<<1|1].e+t[x<<1|1].f));
	t[x].a_b=max(t[x<<1|1].a_b,t[x<<1].a_b+t[x<<1|1].e-t[x<<1|1].f);
	t[x].dc=max(t[x<<1].dc,max(t[x<<1|1].dc-t[x<<1].f+t[x<<1].e,t[x<<1|1].d_c+t[x<<1].f+t[x<<1].e));
	t[x].d_c=max(t[x<<1].d_c,t[x<<1|1].d_c+t[x<<1].f-t[x<<1].e);
	
	t[x].s=max(t[x<<1].ab+t[x<<1|1].d_c,t[x<<1].a_b+t[x<<1|1].dc);
	t[x].s=max(t[x].s,max(t[x<<1].s,t[x<<1|1].s));
	
	t[x].e=t[x<<1].e+max(0,t[x<<1|1].e-t[x<<1].f);
	t[x].f=t[x<<1|1].f+max(0,t[x<<1].f-t[x<<1|1].e);
}
inline void build(int x,int l,int r){
	if(l==r){
		if(s[l]=='(')t[x].ab=t[x].dc=1,t[x].a_b=0,t[x].d_c=1,t[x].e=0,t[x].f=1;
		else t[x].ab=t[x].dc=1,t[x].a_b=1,t[x].d_c=0,t[x].e=1,t[x].f=0;
		t[x].s=1;
		return;
	}
	int mid=(l+r)>>1;
	build(x<<1,l,mid),build(x<<1|1,mid+1,r);
	docnt(x);
}
inline void change(int x,int l,int r,int z){
	if(l==r){
		if(s[l]=='(')t[x].ab=t[x].dc=1,t[x].a_b=0,t[x].d_c=1,t[x].e=0,t[x].f=1;
		else t[x].ab=t[x].dc=1,t[x].a_b=1,t[x].d_c=0,t[x].e=1,t[x].f=0;
		t[x].s=1;
		return;
	}
	int mid=(l+r)>>1;
	if(z<=mid)change(x<<1,l,mid,z);
	else change(x<<1|1,mid+1,r,z);
	docnt(x);
}
int main()
{
	n=read(),m=read(),R=(n-1)<<1;
	scanf("%s",s+1);
	build(1,1,R);
	printf("%d\n",t[1].s);
	for(int i=1;i<=m;i++){
		int u=read(),v=read();
		swap(s[u],s[v]),change(1,1,R,u),change(1,1,R,v);
		printf("%d\n",t[1].s);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43960287/article/details/112122210