题目链接

题意:有一个长度为 \(n\) 的括号序列,你需要支持以下操作:

  1. 将 \([l,r]\) 中所有括号变为 \(c\)
  2. 将 \([l,r]\) 区间翻转
  3. 将 \([l,r]\) 区间中左括号变右括号,右括号变左括号
  4. 求最少需要改变多少个括号才能使得 \([l,r]\) 变成合法括号序列,保证区间长度为偶数。

    \(1 \leq n \leq 10^5\)

基础的 fhq-treap 的题目,主要练下放标记的技巧。

首先我们需要将要求的东西转化为一个式子。例如括号序列 \((())))))((()\),将左右括号抵消掉之后就是 \())))((\),发现抵消完了之后变成了一段左括号跟一段右括号。

我们记 \((=-1\),\()=1\),假设前缀最大值为 \(mx\),后缀最小值为 \(mn\),那么最后会剩下 \(mx\) 个右括号和 \(-mn\) 个左括号,最少需要需要 \(\lceil \frac{mx}{2} \rceil+\lceil -\frac{mn}{2} \rceil\) 次操作。

我们建一棵平衡树,每个节点维护以下六个值:\(sz\) 子树大小,\(sum\) 子树权值和,\(prmn,prmx,sfmn,sfmx\) 表示前缀和后缀的最值,更新方式与最大子段和类似。

对于三个修改操作,我们考虑以下处理方式:

  1. 区间赋值,直接维护标记然后更新 \(sum\) 和 最值。
  2. 区间翻转操作,直接交换左右儿子和前、后缀最大最小值。
  3. 区间取逆操作,实际上就是将每个点的权值变为它的相反数,它的和、前后缀最大最小值也都变为了各自的相反数,如果有赋值标记,那么赋值标记也要取反。需要注意的一点是,最大值取了个相反数之后就变成了最小值,最小值取了相反数之后就变成了最大值,因此还需 swap 一下。

细节还是挺多的,代码也调了不少时间:

  1. //Coded by tzc_wk
  2. /*
  3. 数据不清空,爆零两行泪。
  4. 多测不读完,爆零两行泪。
  5. 边界不特判,爆零两行泪。
  6. 贪心不证明,爆零两行泪。
  7. D P 顺序错,爆零两行泪。
  8. 大小少等号,爆零两行泪。
  9. 变量不统一,爆零两行泪。
  10. 越界不判断,爆零两行泪。
  11. 调试不注释,爆零两行泪。
  12. 溢出不 l l,爆零两行泪。
  13. */
  14. #include <bits/stdc++.h>
  15. using namespace std;
  16. #define fi first
  17. #define se second
  18. #define fz(i,a,b) for(int i=a;i<=b;i++)
  19. #define fd(i,a,b) for(int i=a;i>=b;i--)
  20. #define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
  21. #define all(a) a.begin(),a.end()
  22. #define giveup(...) return printf(__VA_ARGS__),0;
  23. #define fill0(a) memset(a,0,sizeof(a))
  24. #define fill1(a) memset(a,-1,sizeof(a))
  25. #define fillbig(a) memset(a,0x3f,sizeof(a))
  26. #define fillsmall(a) memset(a,0xcf,sizeof(a))
  27. #define mask(a) (1ll<<(a))
  28. #define maskx(a,x) ((a)<<(x))
  29. #define _bit(a,x) (((a)>>(x))&1)
  30. #define _sz(a) ((int)(a).size())
  31. #define filei(a) freopen(a,"r",stdin);
  32. #define fileo(a) freopen(a,"w",stdout);
  33. #define fileio(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
  34. #define eprintf(...) fprintf(stderr,__VA_ARGS__)
  35. #define put(x) putchar(x)
  36. #define eoln put('\n')
  37. #define space put(' ')
  38. #define y1 y_chenxiaoyan_1
  39. #define y0 y_chenxiaoyan_0
  40. typedef pair<int,int> pii;
  41. inline int read(){
  42. int x=0,neg=1;char c=getchar();
  43. while(!isdigit(c)){
  44. if(c=='-') neg=-1;
  45. c=getchar();
  46. }
  47. while(isdigit(c)) x=x*10+c-'0',c=getchar();
  48. return x*neg;
  49. }
  50. inline void print(int x){
  51. if(x<0){
  52. putchar('-');
  53. print(abs(x));
  54. return;
  55. }
  56. if(x<=9) putchar(x+'0');
  57. else{
  58. print(x/10);
  59. putchar(x%10+'0');
  60. }
  61. }
  62. inline int qpow(int x,int e,int _MOD){
  63. int ans=1;
  64. while(e){
  65. if(e&1) ans=ans*x%_MOD;
  66. x=x*x%_MOD;
  67. e>>=1;
  68. }
  69. return ans;
  70. }
  71. int n=read(),m=read();
  72. char str[100005];
  73. struct node{
  74. int ch[2],val,key;
  75. int prmx,prmn,sfmx,sfmn,sum,sz;
  76. int rv_lz,cov_lz,inv_lz;
  77. } s[100005];
  78. int ncnt=0,root;
  79. inline void pushup(int k){
  80. // s[0].prmx=s[0].sfmx=0;s[0].prmn=s[0].sfmn=0x3f3f3f3f;
  81. s[k].prmx=max(s[s[k].ch[0]].prmx,s[s[k].ch[0]].sum+s[k].val+s[s[k].ch[1]].prmx);
  82. s[k].prmn=min(s[s[k].ch[0]].prmn,s[s[k].ch[0]].sum+s[k].val+s[s[k].ch[1]].prmn);
  83. s[k].sfmx=max(s[s[k].ch[1]].sfmx,s[s[k].ch[1]].sum+s[k].val+s[s[k].ch[0]].sfmx);
  84. s[k].sfmn=min(s[s[k].ch[1]].sfmn,s[s[k].ch[1]].sum+s[k].val+s[s[k].ch[0]].sfmn);
  85. s[k].sum=s[s[k].ch[0]].sum+s[s[k].ch[1]].sum+s[k].val;
  86. s[k].sz=s[s[k].ch[0]].sz+s[s[k].ch[1]].sz+1;
  87. }
  88. inline void inv_part(int k){
  89. s[k].val=-s[k].val;s[k].sum=-s[k].sum;
  90. int prmn=s[k].prmn,prmx=s[k].prmx,sfmn=s[k].sfmn,sfmx=s[k].sfmx;
  91. s[k].prmn=-prmx;s[k].prmx=-prmn;s[k].sfmn=-sfmx;s[k].sfmx=-sfmn;
  92. s[k].cov_lz=-s[k].cov_lz;
  93. s[k].inv_lz^=1;
  94. }
  95. inline void cov_part(int k,int mk){
  96. s[k].val=mk;
  97. s[k].sum=mk*s[k].sz;
  98. s[k].cov_lz=mk;
  99. if(mk==1){s[k].prmn=s[k].sfmn=0;s[k].prmx=s[k].sfmx=s[k].sum;}
  100. else{s[k].prmx=s[k].sfmx=0;s[k].prmn=s[k].sfmn=s[k].sum;}
  101. }
  102. inline void rev_part(int k){
  103. swap(s[k].ch[0],s[k].ch[1]);
  104. swap(s[k].prmn,s[k].sfmn);
  105. swap(s[k].prmx,s[k].sfmx);
  106. s[k].rv_lz^=1;
  107. }
  108. inline void pushdown(int k){
  109. if(s[k].inv_lz){
  110. if(s[k].ch[0]) inv_part(s[k].ch[0]);
  111. if(s[k].ch[1]) inv_part(s[k].ch[1]);
  112. s[k].inv_lz=0;
  113. }
  114. if(s[k].cov_lz){
  115. if(s[k].ch[0]) cov_part(s[k].ch[0],s[k].cov_lz);
  116. if(s[k].ch[1]) cov_part(s[k].ch[1],s[k].cov_lz);
  117. s[k].cov_lz=0;
  118. }
  119. if(s[k].rv_lz){
  120. if(s[k].ch[0]) rev_part(s[k].ch[0]);
  121. if(s[k].ch[1]) rev_part(s[k].ch[1]);
  122. s[k].rv_lz=0;
  123. }
  124. }
  125. inline int newnode(char c){
  126. ncnt++;
  127. s[ncnt].key=rand()<<15|rand();
  128. s[ncnt].sz=1;
  129. if(c=='('){
  130. s[ncnt].prmn=s[ncnt].sfmn=-1;
  131. s[ncnt].prmx=s[ncnt].sfmx=0;
  132. s[ncnt].sum=-1;
  133. s[ncnt].val=-1;
  134. }
  135. else{
  136. s[ncnt].prmn=s[ncnt].sfmn=0;
  137. s[ncnt].prmx=s[ncnt].sfmx=1;
  138. s[ncnt].sum=1;
  139. s[ncnt].val=1;
  140. }
  141. return ncnt;
  142. }
  143. inline void build(int &k,int l,int r){
  144. int mid=(l+r)>>1;
  145. k=newnode(str[mid]);
  146. if(l!=mid) build(s[k].ch[0],l,mid-1);
  147. if(r!=mid) build(s[k].ch[1],mid+1,r);
  148. pushup(k);
  149. }
  150. inline void split(int k,int sz,int &a,int &b){
  151. if(!k){
  152. a=b=0;
  153. return;
  154. }
  155. pushdown(k);
  156. if(sz<=s[s[k].ch[0]].sz){
  157. b=k;
  158. split(s[k].ch[0],sz,a,s[k].ch[0]);
  159. }
  160. else{
  161. a=k;
  162. split(s[k].ch[1],sz-s[s[k].ch[0]].sz-1,s[k].ch[1],b);
  163. }
  164. pushup(k);
  165. }
  166. inline int merge(int a,int b){
  167. pushdown(a);pushdown(b);
  168. if(!a||!b) return a+b;
  169. if(s[a].key<s[b].key){
  170. s[a].ch[1]=merge(s[a].ch[1],b);
  171. pushup(a);return a;
  172. }
  173. else{
  174. s[b].ch[0]=merge(a,s[b].ch[0]);
  175. pushup(b);return b;
  176. }
  177. }
  178. inline void rev(int l,int r){
  179. int k1,k2,k3;
  180. split(root,l-1,k1,k2);
  181. split(k2,r-l+1,k2,k3);
  182. rev_part(k2);
  183. root=merge(merge(k1,k2),k3);
  184. }
  185. inline void inv(int l,int r){
  186. int k1,k2,k3;
  187. split(root,l-1,k1,k2);
  188. split(k2,r-l+1,k2,k3);
  189. inv_part(k2);
  190. root=merge(merge(k1,k2),k3);
  191. }
  192. inline void cov(int l,int r,int x){
  193. int k1,k2,k3;
  194. split(root,l-1,k1,k2);
  195. split(k2,r-l+1,k2,k3);
  196. cov_part(k2,x);
  197. root=merge(merge(k1,k2),k3);
  198. }
  199. inline int getf(int x){
  200. if(x&1) return (x>>1)+1;
  201. else return x>>1;
  202. }
  203. inline int query(int l,int r){
  204. int k1,k2,k3;
  205. split(root,l-1,k1,k2);
  206. split(k2,r-l+1,k2,k3);
  207. int res=getf(s[k2].prmx)+getf(abs(s[k2].sfmn));
  208. root=merge(merge(k1,k2),k3);
  209. return res;
  210. }
  211. signed main(){
  212. cin>>str+1;
  213. build(root,1,n);
  214. while(m--){
  215. char opt[10];cin>>opt+1;
  216. if(opt[1]=='R'){
  217. int l=read(),r=read();
  218. char c;cin>>c;
  219. if(c=='(') cov(l,r,-1);
  220. else cov(l,r,1);
  221. }
  222. if(opt[1]=='S'){
  223. int l=read(),r=read();
  224. rev(l,r);
  225. }
  226. if(opt[1]=='I'){
  227. int l=read(),r=read();
  228. inv(l,r);
  229. }
  230. if(opt[1]=='Q'){
  231. int l=read(),r=read();
  232. cout<<query(l,r)<<endl;
  233. }
  234. }
  235. return 0;
  236. }

洛谷 P3215 [HNOI2011]括号修复 / [JSOI2011]括号序列(fhq-treap)的更多相关文章

  1. 【BZOJ2329/2209】[HNOI2011]括号修复/[Jsoi2011]括号序列 Splay

    [BZOJ2329/2209][HNOI2011]括号修复/[Jsoi2011]括号序列 题解:我们的Splay每个节点维护如下东西:左边有多少多余的右括号,右边有多少多余的左括号,同时为了反转操作, ...

  2. [HNOI2011]括号修复 / [JSOI2011]括号序列

    传送门 Solution 一道题花费了两天的时间-- 在大佬@PinkRabbit的帮助下,终于AC了,感动-- 首先,我们考虑一个括号序列被修改成合法序列需要的次数: 我们需要修改的其实是形如... ...

  3. 洛谷P3369 【模板】普通平衡树(FHQ Treap)

    题面 传送门 题解 写了一下\(FHQ\ Treap\) //minamoto #include<bits/stdc++.h> #define R register #define inl ...

  4. 洛谷 P3214 - [HNOI2011]卡农(线性 dp)

    洛谷题面传送门 又是一道我不会的代码超短的题( 一开始想着用生成函数搞,结果怎么都搞不粗来/ll 首先不妨假设音阶之间存在顺序关系,最终答案除以 \(m!\) 即可. 本题个人认为一个比较亮的地方在于 ...

  5. BZOJ 2329: [HNOI2011]括号修复 [splay 括号]

    题目描述 一个合法的括号序列是这样定义的: 空串是合法的. 如果字符串 S 是合法的,则(S)也是合法的. 如果字符串 A 和 B 是合法的,则 AB 也是合法的. 现在给你一个长度为 N 的由‘(' ...

  6. 洛谷P3205 [HNOI2011]合唱队 DP

    原题链接点这里 今天在课上听到了这个题,听完后觉得对于一道\(DP\)题目来说,好的状态定义就意味着一切啊! 来看题: 题目描述 为了在即将到来的晚会上有更好的演出效果,作为AAA合唱队负责人的小A需 ...

  7. 洛谷P3216 [HNOI2011] 数学作业 [矩阵加速,数论]

    题目传送门 数学作业 题目描述 小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题: 给定正整数 N和 M,要求计算 Concatenate (1 .. N)Mod M 的值,其中 C ...

  8. 洛谷 P3216 [HNOI2011]数学作业

    最近学了矩阵,kzj大佬推荐了我这一道题目. 乍一眼看上去,没看出是矩阵,就随便打了一个暴力,30分. 然后仔细分析了一波,发现蛮简单的. 结果全wa了,先看看下面的错误分析吧! 首先,设f[n]为最 ...

  9. 洛谷P3211 [HNOI2011]XOR和路径(期望dp+高斯消元)

    传送门 高斯消元还是一如既往的难打……板子都背不来……Kelin大佬太强啦 不知道大佬们是怎么发现可以按位考虑贡献,求出每一位是$1$的概率 然后设$f[u]$表示$u->n$的路径上这一位为$ ...

随机推荐

  1. python json中的 dumps loads函数

    一.概念理解 1.json.dumps()和json.loads()是json格式处理函数(可以这么理解,json是字符串) (1)json.dumps()函数是将一个Python数据类型列表进行js ...

  2. 【c++ Prime 学习笔记】第4章 表达式

    表达式由一个或多个运算对象组成,对表达式求值返回结果. 字面值和变量是最简单的表达式 把运算符和运算对象组合可得到复杂表达式. 4.1 基础 4.1.1 基本概念 一元运算符作用于一个对象,如取地址符 ...

  3. Java/JDK/J2SE

    Java8与JDK1.8与JDK8与J2SE8与J2SE1.8的区别是什么? Java是面向对象的编程语言,在我们开发Java应用的程序员的专业术语里,Java这个单词其实指的是Java开发工具,也就 ...

  4. redis5集群搭建步骤

    通常情况下为了redis的高可用,我们一般不会使用redis的单实例去运行,一般都会搭建一个 redis 的集群去运行.此处记录一下 redis5 以后 cluster 集群的搭建. 一.需求 red ...

  5. NOIP模拟84(多校17)

    T1 宝藏 解题思路 考场上一眼出 \(nlog^2\) 做法,然后没看见是 1s 3e5 的数据,我竟然以为自己切了?? 考完之后尝试着把二分改为指针的移动,然后就过了??或许是数据水吧,感觉自己的 ...

  6. MyBatis源码分析(八):设计模式

    Mybatis中用到的设计模式 1. 建造者(Builder)模式: 表示一个类的构建与类的表示分离,使得同样的构建过程可以创建不同的表示.建造者模式是一步一步创建一个复杂的对象,他只允许用户只通过指 ...

  7. Spring Cloud Gateway夺命连环10问?

    大家好,我是不才陈某~ 最近有很多小伙伴私信我催更 <Spring Cloud 进阶>,陈某也总结了一下,最终原因就是陈某之前力求一篇文章将一个组件重要知识点讲透,这样导致了文章篇幅很长, ...

  8. 基于live555开发嵌入式linux系统的rtsp直播服务

    最近要搞一个直播服务,车机本身是个前后双路的Dvr,前路1080P 25fps,后路720P 50fps,现在要连接手机app预览实时画面,且支持前后摄像头画面切换. 如果要做直播,这个分辨率和帧率是 ...

  9. Python import commands ImportError: No module named 'commands'

    ImportError: No module named 'commands' 在Python3中执行shell脚本,想要获取其执行状态和标准输出.错误输出 的数据,遇到这个错误,原因是command ...

  10. Typora简介

    Typora是什么 Typora是一款支持实时预览的Markdown文本编辑器,拥有macOS.Windows.Linux三个平台的版本,并且完全免费. 下载地址:https://www.typora ...