浅谈\(splay\):https://www.cnblogs.com/AKMer/p/9979592.html

浅谈\(fhq\)_\(treap\):https://www.cnblogs.com/AKMer/p/9981274.html

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=2329

我们定义左括号为\(1\),右括号为\(-1\)。那么对于一个括号序列,变为合法的步数就是:

\((abs(lnm)+1)/2+(rmx+1)/2\)。\(lmn\)表示前缀最小值,\(rmx\)表示后缀最大值。

至于为什么,自己画一画就明白了。

然后记得\(cov\)标记会清空\(Invert\)标记,下传的时候先传\(cov\)再传\(Int\)。

时间复杂度:\(O((n+m)logn)\)

空间复杂度:\(O(n)\)

\(splay\)版代码如下:

  1. #include <cstdio>
  2. #include <algorithm>
  3. using namespace std;
  4. const int maxn=1e5+5;
  5. int n,m;
  6. int a[maxn];
  7. char s[maxn],ch[10];
  8. int read() {
  9. int x=0,f=1;char ch=getchar();
  10. for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
  11. for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
  12. return x*f;
  13. }
  14. struct Splay {
  15. int tot,root;
  16. int cov[maxn];
  17. bool rev[maxn],Int[maxn];
  18. int son[maxn][2],fa[maxn];
  19. int siz[maxn],val[maxn],sum[maxn];
  20. int lmx[maxn],lmn[maxn],rmx[maxn],rmn[maxn];
  21. void update(int u) {
  22. siz[u]=siz[son[u][0]]+1+siz[son[u][1]];
  23. sum[u]=sum[son[u][0]]+val[u]+sum[son[u][1]];
  24. lmx[u]=max(lmx[son[u][0]],sum[son[u][0]]+val[u]+lmx[son[u][1]]);
  25. lmn[u]=min(lmn[son[u][0]],sum[son[u][0]]+val[u]+lmn[son[u][1]]);
  26. rmx[u]=max(rmx[son[u][1]],sum[son[u][1]]+val[u]+rmx[son[u][0]]);
  27. rmn[u]=min(rmn[son[u][1]],sum[son[u][1]]+val[u]+rmn[son[u][0]]);
  28. }
  29. void build(int l,int r,int lst) {
  30. if(r<l)return;
  31. if(l==r) {
  32. siz[l]=1,val[l]=sum[l]=a[l];
  33. fa[l]=lst,son[lst][l>lst]=l;
  34. lmx[l]=max(0,a[l]),lmn[l]=min(0,a[l]);
  35. rmx[l]=max(0,a[l]),rmn[l]=min(0,a[l]);
  36. return;
  37. }
  38. int mid=(l+r)>>1;
  39. val[mid]=a[mid],fa[mid]=lst;
  40. son[lst][mid>lst]=mid;
  41. build(l,mid-1,mid),build(mid+1,r,mid);
  42. update(mid);
  43. }
  44. void prepare() {
  45. tot=n+2;build(1,n+2,0);root=(n+3)>>1;
  46. }
  47. void add_rev_tag(int p) {
  48. if(!p)return;
  49. rev[p]^=1,swap(son[p][0],son[p][1]);
  50. swap(lmx[p],rmx[p]),swap(lmn[p],rmn[p]);
  51. }
  52. void add_cov_tag(int p,int v) {
  53. if(!p)return;
  54. val[p]=v,sum[p]=siz[p]*v,cov[p]=v,Int[p]=0;
  55. if(v==1)lmx[p]=rmx[p]=siz[p],lmn[p]=rmn[p]=0;
  56. else lmn[p]=rmn[p]=-siz[p],lmx[p]=rmx[p]=0;
  57. }
  58. void add_Int_tag(int p) {
  59. if(!p)return;
  60. Int[p]^=1,sum[p]=0-sum[p];
  61. if(val[p]==1)val[p]=-1;else val[p]=1;
  62. swap(lmx[p],lmn[p]),swap(rmx[p],rmn[p]);
  63. lmx[p]*=-1,lmn[p]*=-1,rmx[p]*=-1,rmn[p]*=-1;
  64. }
  65. void push_down(int u) {
  66. if(cov[u]) {
  67. add_cov_tag(son[u][0],cov[u]);
  68. add_cov_tag(son[u][1],cov[u]);
  69. cov[u]=0;
  70. }
  71. if(Int[u]) {
  72. add_Int_tag(son[u][0]);
  73. add_Int_tag(son[u][1]);
  74. Int[u]=0;
  75. }
  76. if(rev[u]) {
  77. add_rev_tag(son[u][0]);
  78. add_rev_tag(son[u][1]);
  79. rev[u]=0;
  80. }
  81. }
  82. int find(int u,int rk) {
  83. push_down(u);
  84. if(siz[son[u][0]]+1==rk)return u;
  85. if(siz[son[u][0]]>=rk)return find(son[u][0],rk);
  86. return find(son[u][1],rk-siz[son[u][0]]-1);
  87. }
  88. int t(int u) {
  89. return son[fa[u]][1]==u;
  90. }
  91. void rotate(int u) {
  92. int ret=t(u),f=fa[u],s=son[u][ret^1];
  93. son[f][ret]=s;if(s)fa[s]=f;son[u][ret^1]=f;
  94. fa[u]=fa[f];if(fa[f])son[fa[f]][t(f)]=u;
  95. fa[f]=u,update(f),update(u);
  96. }
  97. void splay(int goal,int u) {
  98. int tmp=fa[goal];
  99. while(fa[u]!=tmp) {
  100. if(fa[fa[u]]!=tmp) {
  101. if(t(fa[u])==t(u))rotate(fa[u]);
  102. else rotate(u);
  103. }rotate(u);
  104. }
  105. if(!tmp)root=u;
  106. }
  107. void cover(int l,int r,int v) {
  108. int u1=find(root,l-1),u2=find(root,r+1);
  109. splay(root,u1),splay(son[u1][1],u2);
  110. add_cov_tag(son[u2][0],v);
  111. update(u2),update(u1);
  112. }
  113. void rever(int l,int r) {
  114. int u1=find(root,l-1),u2=find(root,r+1);
  115. splay(root,u1),splay(son[u1][1],u2);
  116. add_rev_tag(son[u2][0]);
  117. update(u2),update(u1);
  118. }
  119. void invert(int l,int r) {
  120. int u1=find(root,l-1),u2=find(root,r+1);
  121. splay(root,u1),splay(son[u1][1],u2);
  122. add_Int_tag(son[u2][0]);
  123. update(u2),update(u1);
  124. }
  125. int query(int l,int r) {
  126. int u1=find(root,l-1),u2=find(root,r+1);
  127. splay(root,u1),splay(son[u1][1],u2);
  128. int u=son[u2][0],tmp=((0-lmn[u])+1)/2+(rmx[u]+1)/2;
  129. return tmp;
  130. }
  131. }T;
  132. int main() {
  133. n=read(),m=read();
  134. scanf("%s",s+2);
  135. for(int i=2;i<=n+1;i++)
  136. if(s[i]=='(')a[i]=1;
  137. else a[i]=-1;
  138. T.prepare();
  139. for(int i=1;i<=m;i++) {
  140. scanf("%s",s+1);
  141. int l=read()+1,r=read()+1;
  142. if(s[1]=='R') {
  143. scanf("%s",ch+1);
  144. if(ch[1]=='(')T.cover(l,r,1);
  145. else T.cover(l,r,-1);
  146. }
  147. if(s[1]=='S')T.rever(l,r);
  148. if(s[1]=='I')T.invert(l,r);
  149. if(s[1]=='Q')printf("%d\n",T.query(l,r));
  150. }
  151. return 0;
  152. }

\(fhq\)_\(treap\)版代码如下:

  1. #include <ctime>
  2. #include <cstdio>
  3. #include <algorithm>
  4. using namespace std;
  5. typedef pair<int,int> pii;
  6. const int maxn=1e5+5;
  7. int n,m;
  8. int a[maxn];
  9. char s[maxn],ch[5];
  10. int read() {
  11. int x=0,f=1;char ch=getchar();
  12. for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
  13. for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
  14. return x*f;
  15. }
  16. struct fhq_treap {
  17. int tot,root;
  18. int cov[maxn];
  19. bool rev[maxn],Int[maxn];
  20. int son[maxn][2],fix[maxn];
  21. int siz[maxn],val[maxn],sum[maxn];
  22. int lmx[maxn],lmn[maxn],rmx[maxn],rmn[maxn];
  23. void update(int p) {
  24. siz[p]=siz[son[p][0]]+1+siz[son[p][1]];
  25. sum[p]=sum[son[p][0]]+val[p]+sum[son[p][1]];
  26. lmx[p]=max(lmx[son[p][0]],sum[son[p][0]]+val[p]+lmx[son[p][1]]);
  27. lmn[p]=min(lmn[son[p][0]],sum[son[p][0]]+val[p]+lmn[son[p][1]]);
  28. rmx[p]=max(rmx[son[p][1]],sum[son[p][1]]+val[p]+rmx[son[p][0]]);
  29. rmn[p]=min(rmn[son[p][1]],sum[son[p][1]]+val[p]+rmn[son[p][0]]);
  30. }
  31. void build(int l,int r,int lst) {
  32. if(r<l)return;
  33. if(l==r) {
  34. siz[l]=1,fix[l]=rand();
  35. son[lst][l>lst]=l;
  36. val[l]=sum[l]=a[l];
  37. lmx[l]=max(0,a[l]),lmn[l]=min(0,a[l]);
  38. rmx[l]=max(0,a[l]),rmn[l]=min(0,a[l]);
  39. return;
  40. }
  41. int mid=(l+r)>>1;
  42. fix[mid]=rand(),val[mid]=a[mid];
  43. son[lst][mid>lst]=mid;
  44. build(l,mid-1,mid);build(mid+1,r,mid);
  45. update(mid);
  46. }
  47. void prepare() {
  48. tot=n;build(1,n,0);root=(n+1)>>1;
  49. }
  50. void add_cov_tag(int u,int v) {
  51. if(!u)return;
  52. val[u]=v,sum[u]=siz[u]*v,cov[u]=v,Int[u]=0;
  53. if(v==1)lmx[u]=rmx[u]=siz[u],lmn[u]=rmn[u]=0;
  54. else lmn[u]=rmn[u]=-siz[u],lmx[u]=rmx[u]=0;
  55. }
  56. void add_Int_tag(int u) {
  57. if(!u)return;
  58. Int[u]^=1,sum[u]=-sum[u];
  59. if(val[u]==1)val[u]=-1;else val[u]=1;
  60. swap(lmn[u],lmx[u]),swap(rmx[u],rmn[u]);
  61. lmn[u]*=-1,lmx[u]*=-1,rmx[u]*=-1,rmn[u]*=-1;
  62. }
  63. void add_rev_tag(int u) {
  64. if(!u)return;
  65. rev[u]^=1,swap(son[u][0],son[u][1]);
  66. swap(lmx[u],rmx[u]),swap(lmn[u],rmn[u]);
  67. }
  68. void push_down(int u) {
  69. if(cov[u]) {
  70. add_cov_tag(son[u][0],cov[u]);
  71. add_cov_tag(son[u][1],cov[u]);
  72. cov[u]=0;
  73. }
  74. if(Int[u]) {
  75. add_Int_tag(son[u][0]);
  76. add_Int_tag(son[u][1]);
  77. Int[u]=0;
  78. }
  79. if(rev[u]) {
  80. add_rev_tag(son[u][0]);
  81. add_rev_tag(son[u][1]);
  82. rev[u]=0;
  83. }
  84. }
  85. pii split(int u,int rk) {
  86. if(!rk)return make_pair(0,u);
  87. if(rk==siz[u])return make_pair(u,0);
  88. push_down(u);
  89. if(siz[son[u][0]]>=rk) {
  90. pii tmp=split(son[u][0],rk);
  91. son[u][0]=tmp.second,update(u);
  92. return make_pair(tmp.first,u);
  93. }
  94. else {
  95. pii tmp=split(son[u][1],rk-siz[son[u][0]]-1);
  96. son[u][1]=tmp.first,update(u);
  97. return make_pair(u,tmp.second);
  98. }
  99. }
  100. int merge(int a,int b) {
  101. if(!a||!b)return a+b;
  102. push_down(a),push_down(b);
  103. if(fix[a]>fix[b])return son[a][1]=merge(son[a][1],b),update(a),a;
  104. else return son[b][0]=merge(a,son[b][0]),update(b),b;
  105. }
  106. void cover(int l,int r,int v) {
  107. pii tmp1=split(root,r);
  108. pii tmp2=split(tmp1.first,l-1);
  109. add_cov_tag(tmp2.second,v);
  110. root=merge(merge(tmp2.first,tmp2.second),tmp1.second);
  111. }
  112. void rever(int l,int r) {
  113. pii tmp1=split(root,r);
  114. pii tmp2=split(tmp1.first,l-1);
  115. add_rev_tag(tmp2.second);
  116. root=merge(merge(tmp2.first,tmp2.second),tmp1.second);
  117. }
  118. void invert(int l,int r) {
  119. pii tmp1=split(root,r);
  120. pii tmp2=split(tmp1.first,l-1);
  121. add_Int_tag(tmp2.second);
  122. root=merge(merge(tmp2.first,tmp2.second),tmp1.second);
  123. }
  124. int query(int l,int r) {
  125. pii tmp1=split(root,r);
  126. pii tmp2=split(tmp1.first,l-1);
  127. int u=tmp2.second,tmp=((0-lmn[u])+1)/2+(rmx[u]+1)/2;
  128. root=merge(merge(tmp2.first,tmp2.second),tmp1.second);
  129. return tmp;
  130. }
  131. }T;
  132. int main() {
  133. n=read(),m=read();
  134. scanf("%s",s+1);
  135. for(int i=1;i<=n;i++)
  136. if(s[i]=='(')a[i]=1;
  137. else a[i]=-1;
  138. T.prepare();
  139. for(int i=1;i<=m;i++) {
  140. scanf("%s",s+1);
  141. int l=read(),r=read();
  142. if(s[1]=='R') {
  143. scanf("%s",ch+1);
  144. if(ch[1]=='(')T.cover(l,r,1);
  145. else T.cover(l,r,-1);
  146. }
  147. if(s[1]=='S')T.rever(l,r);
  148. if(s[1]=='I')T.invert(l,r);
  149. if(s[1]=='Q')printf("%d\n",T.query(l,r));
  150. }
  151. return 0;
  152. }

BZOJ2329:[HNOI2011]括号修复的更多相关文章

  1. bzoj千题计划222:bzoj2329: [HNOI2011]括号修复(fhq treap)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2329 需要改变的括号序列一定长这样 :)))((( 最少改变次数= 多余的‘)’/2 [上取整] + ...

  2. BZOJ2329 [HNOI2011]括号修复

    把左括号看做$1$,右括号看做$-1$,于是查询操作等于查询一个区间左边右边最大(最小)子段和 支持区间翻转,反转,覆盖操作...注意如果有覆盖操作,之前的操作全部作废了...于是在下传标记的时候要最 ...

  3. BZOJ2329 HNOI2011 括号修复 splay+贪心

    找平衡树练习题的时候发现了这道神题,可以说这道题是近几年单考splay的巅峰之作了. 题目大意:给出括号序列,实现区间翻转,区间反转和区间更改.查询区间最少要用几次才能改成合法序列. 分析: 首先我们 ...

  4. 2019.03.25 bzoj2329: [HNOI2011]括号修复(fhq_treap)

    传送门 题意简述: 给一个括号序列,要求支持: 区间覆盖 区间取负 区间翻转 查询把一个区间改成合法括号序列最少改几位 思路: 先考虑静态的时候如何维护答案. 显然把所有合法的都删掉之后序列长这样: ...

  5. BZOJ2329: [HNOI2011]括号修复(Splay)

    解题思路: Replace.Swap.Invert都可以使用Splay完美解决(只需要解决一下标记冲突就好了). 最后只需要统计左右括号冲突就好了. 相当于动态统计最大前缀合和最小后缀和. 因为支持翻 ...

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

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

  7. BZOJ 2329: [HNOI2011]括号修复( splay )

    把括号序列后一定是))))((((这种形式的..所以维护一个最大前缀和l, 最大后缀和r就可以了..答案就是(l+1)/2+(r+1)/2...用splay维护,O(NlogN). 其实还是挺好写的, ...

  8. ●BZOJ 2329 [HNOI2011]括号修复.cpp

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2329 题解: Splay 类似 BZOJ 2329 [HNOI2011]括号修复 只是多了一 ...

  9. 【BZOJ2329】括号修复(Splay)

    [BZOJ2329]括号修复(Splay) 题面 BZOJ 洛谷 题解 本来想着用线段树来写 但是有一个区间翻转 所以不能用线段树了,就只能用平衡树 然后直接\(Splay\)就好了 注意一下几个标记 ...

  10. 【bzoj2329】[HNOI2011]括号修复 Splay

    题目描述 题解 Splay 由于有区间反转操作,因此考虑Splay. 考虑答案:缩完括号序列后剩下的一定是 $a$ 个')'+ $b$ 个'(',容易发现答案等于 $\lceil\frac a2\rc ...

随机推荐

  1. SQL Server中排名函数row_number,rank,dense_rank,ntile详解

    SQL Server中排名函数row_number,rank,dense_rank,ntile详解 从SQL SERVER2005开始,SQL SERVER新增了四个排名函数,分别如下:1.row_n ...

  2. 【PyCharm编辑器】之报:Spellchecker inspection helps locate typos and misspelling in your code, comments and literals, and fix them in one click.问题

    如上图,输入一个单词时会出现波浪线,报:Spellchecker inspection helps locate typos and misspelling in your code, comment ...

  3. 转载 ---原生和H5交互挺多的,最近也有朋友再问。这儿我写个简单的例子给大家 直接贴代码 js的

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> ...

  4. 自我总结- CGAffineTransform

    在应用中我们经常需要做一些仿射变换 可以用于 平移.旋转.缩放变换路径: View有一个属性transform 可以指定一个 CGAffineTransform 即可完成仿射变换 1.平移变换 // ...

  5. (转)ConcurrentModificationException异常原因和解决方法

    原文地址: http://www.cnblogs.com/dolphin0520/p/3933551.html 一.ConcurrentModificationException异常出现的原因 先看下 ...

  6. EasyPlayer RTSP播放器对RTSP播放地址url的通用兼容修改意见

    问题反馈 最近在线上遇到一位老朋友咨询关于EasyPlayer播放器的事情,大概现象就是分别用EasyPlayer和vlc播放大华摄像机的RTSP流,流地址是:rtsp://admin:admin12 ...

  7. java 核心技术卷一 知识点

    第九章 集合 1.Iterator和Iterable接口类,作用. 2.Collection接口类,作用. 3.Map接口类,作用.

  8. 创建laravel项目

    下载项目到本地 git clone https://github.com/251068550/LaraBlog.git compoer安装 cd LaraBlog composer install 如 ...

  9. 流畅python学习笔记第十八章:使用asyncio包处理并发(一)

    首先是线程与协程的对比.在文中作者通过一个实例分别采用线程实现和asynchio包实现来比较两者的差别.在多线程的样例中,会用到join的方法,下面来介绍下join方法的使用. 知识点一:当一个进程启 ...

  10. Linux就该这么学--命令集合9(环境变量)

    1.alias命令用于设置命令的别名:(alias 别名=命令) alias lll ="ll" 2.unalias命令用于取消命令的别名:(unalias 别名) unalias ...