Codeforces 题目传送门 & 洛谷题目传送门

首先考虑这个所谓的“括号树”与直径的本质是什么。考虑括号树上两点 \(x,y\),我们不妨用一个“DFS”的过程来理解,在 DFS 过程中假设我们在第 \(l\) 个字符后访问 \(x\),显然接下来会访问 \(x\) 的子树并回到 \(x\),也就是说对应的括号序列是一个合法括号序列,也就是说它的左右括号相抵消了,紧接着我们会向上回溯到 \(\text{LCA}(x,y)\),对于在回溯的过程中访问的点 \(z\),我们可能还会访问它的其它子树,不过由于最终回到了 \(z\),所经过的括号串一定是一个合法括号序列,最终不能相抵消的部分一定是 \(dep_x-dep_{\text{LCA}(x,y)}\) 个右括号,换句话说,从 \(x\) 到 \(\text{LCA}(x,y)\),其经过的路径进行左右括号抵消后一定是若干个右括号拼起来的字符串。同理,从 \(\text{LCA}(x,y)\to y\) 一定是若干个左括号拼起来的字符串,也就是说 \(x,y\) 之间的路径长度就是 \([l,r]\) 进行左括号相抵消后剩余部分的长度,我们记该值为 \(f(l,r)\)。而显然 \(\forall 1\leq l\leq r\leq 2(n-1)\),区间 \([l,r]\) 都对应一对 \((x,y)\)。故答案即为 \(\max\limits_{1\leq l\leq r\leq 2(n-1)}f(l,r)\)。

然后我就在那儿一直想怎样直接维护 \(f(l,r)\),心态爆炸……似乎 ycx 也卡在了这个地方?

根据 \(f(l,r)\) 的定义不难发现这玩意儿直接维护是不太容易的,因为合并两个区间时还需考虑左右括号相消的问题。如果我们能够将其变成类似于求和、取 \(\max\) 的东西是不是就比较好维护了呢?

我们假设 \([l,r]\) 消完之后剩余 \(x\) 个右括号,\(y\) 个左括号。考虑套路地将 ( 看作 \(1\),) 看作 \(-1\)。对 \([l,r]\) 进行一遍前缀和得到数组 \(s_i\)(或者说 \(s_i\) 表示区间 \([l,i]\) 中左括号个数 \(-\) 右括号个数),那么显然 \(\min_{i=l}^rs_i=-x\)。

看到这个 \(\min\) 能想到什么呢?

考虑设 \(s_k=-x\),我们不妨将区间 \([l,r]\) 从 \(k\) 处劈开,劈成两个子区间 \([l,k],[k+1,r]\),显然 \([l,k]\) 中左右相消后一定是 \(x\) 个左括号,\([k+1,r]\) 中左右相消后一定是 \(y\) 个右括号。如果我们记 \(sum(l,r)\) 为 \([l,r]\) 中所有数字和。那么有 \(sum(l,k)=-x,sum(k+1,r)=y\),故 \(sum(k+1,r)-sum(l,k)=x+y\)。而对于某个 \(k'\in[l,r),k'\neq k\),由 \(\min_{i=l}^rs_i=-x\) 知 \(s_k\le s'_k\) 知 \(sum(k+1,r)-sum(l,k')=sum(l,r)-2sum(l,k)=sum(l,r)-2s_{k'}\le sum(l,r)-2s_k=x+y\),故 \(f(l,r)=x+y=\max\limits_{k=l}^{r-1}\{sum(k+1,r)-sum(l,k)\}\)

于是最终答案即为 \(\max\limits_{1\leq l\leq r\leq 2(n-1)}\max\limits_{k=l}^{r-1}\{sum(k+1,r)-sum(l,k)\}\),也就是第一篇题解中所说的“选择相邻两段并做差的最大值”。

这个就可以用线段树维护了,每个节点 \([l,r]\) 维护以下八个值:

  • \(sum\) 表示 \(sum(l,r)\)
  • \(lmx\) 表示 \(\max sum(l,k)\)
  • \(rmx\) 表示 \(\max sum(k,r)\)
  • \(lmn\) 表示 \(\min sum(l,k)\)
  • \(rmn\) 表示 \(\min sum(k,r)\)
  • \(mx1\) 表示 \(\max sum(x,y)-sum(l,x),l\leq x\le y\le r\)
  • \(mx2\) 表示 \(\max sum(y,x)-sum(x,y),l\leq x\leq y\le r\)
  • \(mx\) 表示 \(\max sum(y,z)-sum(x,y),l\leq x\leq y\leq z\leq r\)

以上八个标记都可 \(\mathcal O(1)\) pushup,具体见代码。

至于修改……这个就相当容易了罢,直接单点修改即可。

时间复杂度线对。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=2e5;
int n,qu;char str[MAXN+5];
struct node{int l,r,sum,lmx,rmx,lmn,rmn,mx1,mx2,mx;} s[MAXN*4+5];
void pushup(int k){
s[k].sum=s[k<<1].sum+s[k<<1|1].sum;
s[k].lmx=max(s[k<<1].lmx,s[k<<1].sum+s[k<<1|1].lmx);
s[k].lmn=min(s[k<<1].lmn,s[k<<1].sum+s[k<<1|1].lmn);
s[k].rmx=max(s[k<<1|1].rmx,s[k<<1|1].sum+s[k<<1].rmx);
s[k].rmn=min(s[k<<1|1].rmn,s[k<<1|1].sum+s[k<<1].rmn);
s[k].mx1=max(s[k<<1].mx1,max(-s[k<<1].sum+s[k<<1|1].mx1,s[k<<1|1].lmx+s[k<<1].rmx*2-s[k<<1].sum));
s[k].mx2=max(s[k<<1|1].mx2,max(s[k<<1|1].sum+s[k<<1].mx2,-s[k<<1].rmn+s[k<<1|1].sum-2*s[k<<1|1].lmn));
s[k].mx=max(max(s[k<<1].mx,s[k<<1|1].mx),max(s[k<<1].mx2+s[k<<1|1].lmx,-s[k<<1].rmn+s[k<<1|1].mx1));
}
void build(int k=1,int l=1,int r=n){
s[k].l=l;s[k].r=r;
if(l==r){
if(str[l]=='(') s[k].sum=1,s[k].lmx=1,s[k].rmx=1,s[k].lmn=0,s[k].rmn=0;
else s[k].sum=-1,s[k].lmx=0,s[k].rmx=0,s[k].lmn=-1,s[k].rmn=-1;
s[k].mx1=1;s[k].mx2=1;s[k].mx=1;return;
} int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
pushup(k);
}
void modify(int k,int p,int v){
if(s[k].l==s[k].r){
s[k].lmx=s[k].rmx=max(v,0);
s[k].lmn=s[k].rmn=min(v,0);
s[k].sum=v;
s[k].mx1=1;s[k].mx2=1;s[k].mx=1;return;
} int mid=s[k].l+s[k].r>>1;
if(p<=mid) modify(k<<1,p,v);
else modify(k<<1|1,p,v);
pushup(k);
}
int main(){
scanf("%d%d%s",&n,&qu,str+1);n=(n-1)<<1;
build(1,1,n);printf("%d\n",s[1].mx);
while(qu--){
int x,y;scanf("%d%d",&x,&y);
if(str[x]!=str[y]){
swap(str[x],str[y]);
modify(1,x,(str[x]=='(')?1:-1);
modify(1,y,(str[y]=='(')?1:-1);
} printf("%d\n",s[1].mx);
}
return 0;
}

Codeforces 1149C - Tree Generator™(线段树+转化+标记维护)的更多相关文章

  1. codeforces 447E or 446C 线段树 + fib性质或二次剩余性质

    CF446C题意: 给你一个数列\(a_i\),有两种操作:区间求和:\(\sum_{i=l}^{r}(a[i]+=fib[i-l+1])\).\(fib\)是斐波那契数列. 思路 (一) codef ...

  2. [Codeforces 1199D]Welfare State(线段树)

    [Codeforces 1199D]Welfare State(线段树) 题面 给出一个长度为n的序列,有q次操作,操作有2种 1.单点修改,把\(a_x\)修改成y 2.区间修改,把序列中值< ...

  3. hdu-3397 Sequence operation 线段树多种标记

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3397 题目大意: 0 a b表示a-b区间置为0 1 a b表示a-b区间置为1 2 a b表示a- ...

  4. HDU 3468:A Simple Problem with Integers(线段树+延迟标记)

    A Simple Problem with Integers Case Time Limit: 2000MS Description You have N integers, A1, A2, ... ...

  5. [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)

    [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...

  6. [Codeforces 316E3]Summer Homework(线段树+斐波那契数列)

    [Codeforces 316E3]Summer Homework(线段树+斐波那契数列) 顺便安利一下这个博客,给了我很大启发(https://gaisaiyuno.github.io/) 题面 有 ...

  7. CodeForces 228D. Zigzag(线段树暴力)

    D. Zigzag time limit per test 3 seconds memory limit per test 256 megabytes input standard input out ...

  8. hdu 5274 Dylans loves tree(LCA + 线段树)

    Dylans loves tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  9. BZOJ_2212_[Poi2011]Tree Rotations_线段树合并

    BZOJ_2212_[Poi2011]Tree Rotations_线段树合并 Description Byteasar the gardener is growing a rare tree cal ...

随机推荐

  1. SpringCloud微服务实战——搭建企业级开发框架(五):数据库持久化集成MySql+Druid+MyBatis-Plus

      在引入相关数据库持久化相关依赖库之前,我们可以考虑到,当我们因业务开发需要,引入各种各样的依赖库时,Jar包冲突是我们必须面对的一个问题,Spring为了解决这些Jar包的冲突,推出了各种bom, ...

  2. AIApe问答机器人Scrum Meeting 5.5&5.6

    Scrum Meeting 7 日期:2021年5月5日&2021年5月6日 会议主要内容概述:汇报近日工作,确定下一步计划,放弃"关键词提取"和"改进关键词&q ...

  3. 大闸蟹的 O O 第三单元日子——中测与强测的惨烈修罗场

    第三单元是大闸蟹体验及其差的一单元,鬼知道从一开始的自信慢慢到最后的自暴自弃我都经历了什么,我已经感觉到分数与gpa与头发都在渐渐和我说再见了 JML基础梳理及工具链 JML(Java Modelin ...

  4. Noip模拟54 2021.9.16

    T1 选择 现在发现好多题目都是隐含的状压,不明面给到数据范围里,之凭借一句话 比如这道题就是按照题目里边给的儿子数量不超过$10$做状压,非常邪门 由于数据范围比较小,怎么暴力就怎么来 从叶子节点向 ...

  5. 2021.6.17考试总结[NOIP模拟8]

    T1 星际旅行 其实就是求两条只走一遍的边的方案数. 考场上第一眼就感觉不可做,后来画了几个图,发现好像只要两个边是相连的就可以只走一遍,居然还真拿了30.. 其实是一道欧拉路的题,把每条非自环的边看 ...

  6. 攻防世界 杂项 6.pure_color

    图片隐写 工具 使用StegSolve一把梭 另一种解法 右击图片编辑,画图工具打开,属性设置黑白.

  7. 算法:汉诺塔问题(Tower of Brahma puzzle)

    一.算法背景 最早发明这个问题的人是法国数学家爱德华·卢卡斯.传说越南河内某间寺院有三根银棒(A, B, C),上串 64 个金盘. 寺院里的僧侣依照一个古老的预言,以上述规则移动这些盘子:预言说当这 ...

  8. Verdi UVM Debug Mode 简单使用

    转载:Verdi UVM Debug Mode 简单使用_Holden_Liu的博客-CSDN博客 文档与源码: User Guide: UVMDebugUserGuide.pdf  in $VERD ...

  9. Luogu P1297 [国家集训队]单选错位 | 概率与期望

    题目链接 题解: 单独考虑每一道题目对答案的贡献. 设$g_i$表示gx在第$i$道题目的答案是否正确(1表示正确,0表示不正确),则$P(g_i=1)$表示gx在第$i$道题目的答案正确的概率. 我 ...

  10. JAVA笔记15__TCP服务端、客户端程序 / ECHO程序 /

    /** * TCP:传输控制协议,采用三方握手的方式,保证准确的连接操作. * UDP:数据报协议,发送数据报,例如:手机短信或者是QQ消息. */ /** * TCP服务器端程序 */ public ...