浅谈\(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\)版代码如下:

#include <cstdio>
#include <algorithm>
using namespace std; const int maxn=1e5+5; int n,m;
int a[maxn];
char s[maxn],ch[10]; int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
} struct Splay {
int tot,root;
int cov[maxn];
bool rev[maxn],Int[maxn];
int son[maxn][2],fa[maxn];
int siz[maxn],val[maxn],sum[maxn];
int lmx[maxn],lmn[maxn],rmx[maxn],rmn[maxn]; void update(int u) {
siz[u]=siz[son[u][0]]+1+siz[son[u][1]];
sum[u]=sum[son[u][0]]+val[u]+sum[son[u][1]];
lmx[u]=max(lmx[son[u][0]],sum[son[u][0]]+val[u]+lmx[son[u][1]]);
lmn[u]=min(lmn[son[u][0]],sum[son[u][0]]+val[u]+lmn[son[u][1]]);
rmx[u]=max(rmx[son[u][1]],sum[son[u][1]]+val[u]+rmx[son[u][0]]);
rmn[u]=min(rmn[son[u][1]],sum[son[u][1]]+val[u]+rmn[son[u][0]]);
} void build(int l,int r,int lst) {
if(r<l)return;
if(l==r) {
siz[l]=1,val[l]=sum[l]=a[l];
fa[l]=lst,son[lst][l>lst]=l;
lmx[l]=max(0,a[l]),lmn[l]=min(0,a[l]);
rmx[l]=max(0,a[l]),rmn[l]=min(0,a[l]);
return;
}
int mid=(l+r)>>1;
val[mid]=a[mid],fa[mid]=lst;
son[lst][mid>lst]=mid;
build(l,mid-1,mid),build(mid+1,r,mid);
update(mid);
} void prepare() {
tot=n+2;build(1,n+2,0);root=(n+3)>>1;
} void add_rev_tag(int p) {
if(!p)return;
rev[p]^=1,swap(son[p][0],son[p][1]);
swap(lmx[p],rmx[p]),swap(lmn[p],rmn[p]);
} void add_cov_tag(int p,int v) {
if(!p)return;
val[p]=v,sum[p]=siz[p]*v,cov[p]=v,Int[p]=0;
if(v==1)lmx[p]=rmx[p]=siz[p],lmn[p]=rmn[p]=0;
else lmn[p]=rmn[p]=-siz[p],lmx[p]=rmx[p]=0;
} void add_Int_tag(int p) {
if(!p)return;
Int[p]^=1,sum[p]=0-sum[p];
if(val[p]==1)val[p]=-1;else val[p]=1;
swap(lmx[p],lmn[p]),swap(rmx[p],rmn[p]);
lmx[p]*=-1,lmn[p]*=-1,rmx[p]*=-1,rmn[p]*=-1;
} void push_down(int u) {
if(cov[u]) {
add_cov_tag(son[u][0],cov[u]);
add_cov_tag(son[u][1],cov[u]);
cov[u]=0;
}
if(Int[u]) {
add_Int_tag(son[u][0]);
add_Int_tag(son[u][1]);
Int[u]=0;
}
if(rev[u]) {
add_rev_tag(son[u][0]);
add_rev_tag(son[u][1]);
rev[u]=0;
}
} int find(int u,int rk) {
push_down(u);
if(siz[son[u][0]]+1==rk)return u;
if(siz[son[u][0]]>=rk)return find(son[u][0],rk);
return find(son[u][1],rk-siz[son[u][0]]-1);
} int t(int u) {
return son[fa[u]][1]==u;
} void rotate(int u) {
int ret=t(u),f=fa[u],s=son[u][ret^1];
son[f][ret]=s;if(s)fa[s]=f;son[u][ret^1]=f;
fa[u]=fa[f];if(fa[f])son[fa[f]][t(f)]=u;
fa[f]=u,update(f),update(u);
} void splay(int goal,int u) {
int tmp=fa[goal];
while(fa[u]!=tmp) {
if(fa[fa[u]]!=tmp) {
if(t(fa[u])==t(u))rotate(fa[u]);
else rotate(u);
}rotate(u);
}
if(!tmp)root=u;
} void cover(int l,int r,int v) {
int u1=find(root,l-1),u2=find(root,r+1);
splay(root,u1),splay(son[u1][1],u2);
add_cov_tag(son[u2][0],v);
update(u2),update(u1);
} void rever(int l,int r) {
int u1=find(root,l-1),u2=find(root,r+1);
splay(root,u1),splay(son[u1][1],u2);
add_rev_tag(son[u2][0]);
update(u2),update(u1);
} void invert(int l,int r) {
int u1=find(root,l-1),u2=find(root,r+1);
splay(root,u1),splay(son[u1][1],u2);
add_Int_tag(son[u2][0]);
update(u2),update(u1);
} int query(int l,int r) {
int u1=find(root,l-1),u2=find(root,r+1);
splay(root,u1),splay(son[u1][1],u2);
int u=son[u2][0],tmp=((0-lmn[u])+1)/2+(rmx[u]+1)/2;
return tmp;
}
}T; int main() {
n=read(),m=read();
scanf("%s",s+2);
for(int i=2;i<=n+1;i++)
if(s[i]=='(')a[i]=1;
else a[i]=-1;
T.prepare();
for(int i=1;i<=m;i++) {
scanf("%s",s+1);
int l=read()+1,r=read()+1;
if(s[1]=='R') {
scanf("%s",ch+1);
if(ch[1]=='(')T.cover(l,r,1);
else T.cover(l,r,-1);
}
if(s[1]=='S')T.rever(l,r);
if(s[1]=='I')T.invert(l,r);
if(s[1]=='Q')printf("%d\n",T.query(l,r));
}
return 0;
}

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

#include <ctime>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef pair<int,int> pii; const int maxn=1e5+5; int n,m;
int a[maxn];
char s[maxn],ch[5]; int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
} struct fhq_treap {
int tot,root;
int cov[maxn];
bool rev[maxn],Int[maxn];
int son[maxn][2],fix[maxn];
int siz[maxn],val[maxn],sum[maxn];
int lmx[maxn],lmn[maxn],rmx[maxn],rmn[maxn]; void update(int p) {
siz[p]=siz[son[p][0]]+1+siz[son[p][1]];
sum[p]=sum[son[p][0]]+val[p]+sum[son[p][1]];
lmx[p]=max(lmx[son[p][0]],sum[son[p][0]]+val[p]+lmx[son[p][1]]);
lmn[p]=min(lmn[son[p][0]],sum[son[p][0]]+val[p]+lmn[son[p][1]]);
rmx[p]=max(rmx[son[p][1]],sum[son[p][1]]+val[p]+rmx[son[p][0]]);
rmn[p]=min(rmn[son[p][1]],sum[son[p][1]]+val[p]+rmn[son[p][0]]);
} void build(int l,int r,int lst) {
if(r<l)return;
if(l==r) {
siz[l]=1,fix[l]=rand();
son[lst][l>lst]=l;
val[l]=sum[l]=a[l];
lmx[l]=max(0,a[l]),lmn[l]=min(0,a[l]);
rmx[l]=max(0,a[l]),rmn[l]=min(0,a[l]);
return;
}
int mid=(l+r)>>1;
fix[mid]=rand(),val[mid]=a[mid];
son[lst][mid>lst]=mid;
build(l,mid-1,mid);build(mid+1,r,mid);
update(mid);
} void prepare() {
tot=n;build(1,n,0);root=(n+1)>>1;
} void add_cov_tag(int u,int v) {
if(!u)return;
val[u]=v,sum[u]=siz[u]*v,cov[u]=v,Int[u]=0;
if(v==1)lmx[u]=rmx[u]=siz[u],lmn[u]=rmn[u]=0;
else lmn[u]=rmn[u]=-siz[u],lmx[u]=rmx[u]=0;
} void add_Int_tag(int u) {
if(!u)return;
Int[u]^=1,sum[u]=-sum[u];
if(val[u]==1)val[u]=-1;else val[u]=1;
swap(lmn[u],lmx[u]),swap(rmx[u],rmn[u]);
lmn[u]*=-1,lmx[u]*=-1,rmx[u]*=-1,rmn[u]*=-1;
} void add_rev_tag(int u) {
if(!u)return;
rev[u]^=1,swap(son[u][0],son[u][1]);
swap(lmx[u],rmx[u]),swap(lmn[u],rmn[u]);
} void push_down(int u) {
if(cov[u]) {
add_cov_tag(son[u][0],cov[u]);
add_cov_tag(son[u][1],cov[u]);
cov[u]=0;
}
if(Int[u]) {
add_Int_tag(son[u][0]);
add_Int_tag(son[u][1]);
Int[u]=0;
}
if(rev[u]) {
add_rev_tag(son[u][0]);
add_rev_tag(son[u][1]);
rev[u]=0;
}
} pii split(int u,int rk) {
if(!rk)return make_pair(0,u);
if(rk==siz[u])return make_pair(u,0);
push_down(u);
if(siz[son[u][0]]>=rk) {
pii tmp=split(son[u][0],rk);
son[u][0]=tmp.second,update(u);
return make_pair(tmp.first,u);
}
else {
pii tmp=split(son[u][1],rk-siz[son[u][0]]-1);
son[u][1]=tmp.first,update(u);
return make_pair(u,tmp.second);
}
} int merge(int a,int b) {
if(!a||!b)return a+b;
push_down(a),push_down(b);
if(fix[a]>fix[b])return son[a][1]=merge(son[a][1],b),update(a),a;
else return son[b][0]=merge(a,son[b][0]),update(b),b;
} void cover(int l,int r,int v) {
pii tmp1=split(root,r);
pii tmp2=split(tmp1.first,l-1);
add_cov_tag(tmp2.second,v);
root=merge(merge(tmp2.first,tmp2.second),tmp1.second);
} void rever(int l,int r) {
pii tmp1=split(root,r);
pii tmp2=split(tmp1.first,l-1);
add_rev_tag(tmp2.second);
root=merge(merge(tmp2.first,tmp2.second),tmp1.second);
} void invert(int l,int r) {
pii tmp1=split(root,r);
pii tmp2=split(tmp1.first,l-1);
add_Int_tag(tmp2.second);
root=merge(merge(tmp2.first,tmp2.second),tmp1.second);
} int query(int l,int r) {
pii tmp1=split(root,r);
pii tmp2=split(tmp1.first,l-1);
int u=tmp2.second,tmp=((0-lmn[u])+1)/2+(rmx[u]+1)/2;
root=merge(merge(tmp2.first,tmp2.second),tmp1.second);
return tmp;
}
}T; int main() {
n=read(),m=read();
scanf("%s",s+1);
for(int i=1;i<=n;i++)
if(s[i]=='(')a[i]=1;
else a[i]=-1;
T.prepare();
for(int i=1;i<=m;i++) {
scanf("%s",s+1);
int l=read(),r=read();
if(s[1]=='R') {
scanf("%s",ch+1);
if(ch[1]=='(')T.cover(l,r,1);
else T.cover(l,r,-1);
}
if(s[1]=='S')T.rever(l,r);
if(s[1]=='I')T.invert(l,r);
if(s[1]=='Q')printf("%d\n",T.query(l,r));
}
return 0;
}

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. PHP第四课 了解经常使用的函数

    学习概要: 一.语言结构 二.自己定义函数 三.变量作用域 四.静态变量 五.函数返回值 六.參数 七.默认參数 八.引用參数 九.可变个数函数 十.回调函数 十一.变量函数 十二.递归函数 十三.文 ...

  2. Spring Security 表单登录

    1. 简介 本文将重点介绍使用Spring Security登录. 本文将构建在之前简单的Spring MVC示例之上,因为这是设置Web应用程序和登录机制的必不可少的. 2. Maven 依赖 要将 ...

  3. matlab2016b-linux版本在ubutu16.04x64上面不能打开摄像头的处理方法

    this  can  not  work.    need  find  other way.   ================================================== ...

  4. jquery 获取 outerHtml

    在开发过程中,jQuery.html() 是获取当前节点下的html代码,并不包括当前节点本身的代码,然后我们有时候确须要.找遍jQuery api文档也没有不论什么方法能够拿到. 看到有的人通过pa ...

  5. delphi 解析Json格式(转自:http://blog.csdn.net/jayqiang/article/details/7066824)

    SuperObject 是开源的 Delphi 的 JSON 工具包,可生成 JSON 数据以及进行 JSON 解析. unit Unit6; interface uses Windows, Mess ...

  6. Git分支中的远程操作实践

    Git分支中的远程操作实践 前几篇博客陆陆续续的讲了好多关于Git操作的内容, 其中在上篇博客聊了<Git中的merge.rebase.cherry-pick以及交互式rebase>,本篇 ...

  7. ant 可自动替换友盟渠道、版本号、包名

    可自动替换友盟渠道.版本号.包名 如何集成到我的项目里 前提:了解android官方文档,在项目目录中执行ant debug能打包,比如常见的打包步骤: android update project ...

  8. programming review (c++): (1)vector, linked list, stack, queue, map, string, bit manipulation

    编程题常用知识点的review. most important: 想好(1)详尽步骤(2)边界特例,再开始写代码. I.vector #include <iostream> //0.头文件 ...

  9. 1930: [Shoi2003]pacman 吃豆豆

    1930: [Shoi2003]pacman 吃豆豆 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1969  Solved: 461[Submit][ ...

  10. Spanner: Google’s Globally-Distributed Database

    https://research.google.com/archive/spanner.html Spanner is Google’s scalable, multi-version, global ...