【Codeforces】 CF1149C. Tree Generator™

题目链接

Codeforces方向

Luogu方向

题目解法

首先给出一个引理

一段序列去掉所有的匹配括号之后,剩下的序列一定组成一条链,且这条链的长度就是剩下序列的长度

可以粗糙地证明一下:

学过了树上莫队的知道:原题中的括号序列可以转化为欧拉序

树上的一条路径可以分成 2 种情况,记 first[x] 为 x 第一次在欧拉序中出现的位置, last[x] 同理,这里默认 first[u] < first[v]

  1. last[u] > last[v],那么 u 一定是 v 的祖先,那么 first[u] 到 first[v] 去掉匹配的就是 u 到 v 路径的长度 +1
    一条像这样的路径只有通到根节点 1 才是最优的,但是 1 并不在括号序列内,所以 +1 可以抵消掉
  2. last[u] < last[v],那么 u 一定不是 v 的祖先,从 last[u] 到 first[v] 去掉匹配的路径是不包括 lca 的,因为点数 = 边数 +1,所以成立

其实上面画几个图感性理解一下就可以了

观察去掉匹配括号后,序列一定是 ))…)(…(( 类似这样的,其中 ( 和 ) 都可以没有

我们考虑把 ( 赋值为 1,) 赋值为 -1

那么路径的长度一定是找到一个点 p,从 p 往后的前缀和 - 从 p 往前的后缀和

从中找到的最大值

这个东西可以用线段树维护一下

想象需要记录那些东西:

前缀的最大相减值,后缀的最大相减值,把 [ l,r ] 填满的最大相减值, 总和,前缀和最大值,后缀和最小值,答案

通过这些值可以进行转移

#include 
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<>1;
		if(mid>=p)
			modify(l,mid,x<<1,p,k);
		else
			modify(mid+1,r,x<<1^1,p,k);
		pushup(x);
//		cout<

你可能感兴趣的:(Codeforces,算法)