BZOJ2329:[HNOI2011]括号修复
浅谈\(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]括号修复的更多相关文章
- bzoj千题计划222:bzoj2329: [HNOI2011]括号修复(fhq treap)
http://www.lydsy.com/JudgeOnline/problem.php?id=2329 需要改变的括号序列一定长这样 :)))((( 最少改变次数= 多余的‘)’/2 [上取整] + ...
- BZOJ2329 [HNOI2011]括号修复
把左括号看做$1$,右括号看做$-1$,于是查询操作等于查询一个区间左边右边最大(最小)子段和 支持区间翻转,反转,覆盖操作...注意如果有覆盖操作,之前的操作全部作废了...于是在下传标记的时候要最 ...
- BZOJ2329 HNOI2011 括号修复 splay+贪心
找平衡树练习题的时候发现了这道神题,可以说这道题是近几年单考splay的巅峰之作了. 题目大意:给出括号序列,实现区间翻转,区间反转和区间更改.查询区间最少要用几次才能改成合法序列. 分析: 首先我们 ...
- 2019.03.25 bzoj2329: [HNOI2011]括号修复(fhq_treap)
传送门 题意简述: 给一个括号序列,要求支持: 区间覆盖 区间取负 区间翻转 查询把一个区间改成合法括号序列最少改几位 思路: 先考虑静态的时候如何维护答案. 显然把所有合法的都删掉之后序列长这样: ...
- BZOJ2329: [HNOI2011]括号修复(Splay)
解题思路: Replace.Swap.Invert都可以使用Splay完美解决(只需要解决一下标记冲突就好了). 最后只需要统计左右括号冲突就好了. 相当于动态统计最大前缀合和最小后缀和. 因为支持翻 ...
- 【BZOJ2329/2209】[HNOI2011]括号修复/[Jsoi2011]括号序列 Splay
[BZOJ2329/2209][HNOI2011]括号修复/[Jsoi2011]括号序列 题解:我们的Splay每个节点维护如下东西:左边有多少多余的右括号,右边有多少多余的左括号,同时为了反转操作, ...
- BZOJ 2329: [HNOI2011]括号修复( splay )
把括号序列后一定是))))((((这种形式的..所以维护一个最大前缀和l, 最大后缀和r就可以了..答案就是(l+1)/2+(r+1)/2...用splay维护,O(NlogN). 其实还是挺好写的, ...
- ●BZOJ 2329 [HNOI2011]括号修复.cpp
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2329 题解: Splay 类似 BZOJ 2329 [HNOI2011]括号修复 只是多了一 ...
- 【BZOJ2329】括号修复(Splay)
[BZOJ2329]括号修复(Splay) 题面 BZOJ 洛谷 题解 本来想着用线段树来写 但是有一个区间翻转 所以不能用线段树了,就只能用平衡树 然后直接\(Splay\)就好了 注意一下几个标记 ...
- 【bzoj2329】[HNOI2011]括号修复 Splay
题目描述 题解 Splay 由于有区间反转操作,因此考虑Splay. 考虑答案:缩完括号序列后剩下的一定是 $a$ 个')'+ $b$ 个'(',容易发现答案等于 $\lceil\frac a2\rc ...
随机推荐
- jQuery源代码 框架分析
每个框架都有一个核心.全部的结构都是基于这个核心之上,结构建立好了之后,剩下的就是功能的堆砌. jQuery的核心就是从HTML文档中匹配元素并对其操作. 就跟一座大楼一样.让我们一步一步了解这座大厦 ...
- oracle中视图v$sql的用途
1.获取正在执行的sql语句.sql语句的执行时间.sql语句的等待事件: select a.sql_text,b.status,b.last_call_et,b.machine,b.event,b. ...
- 【打CF,学算法——一星级】Codeforces Round #313 (Div. 2) A. Currency System in Geraldion
[CF简单介绍] 提交链接:http://codeforces.com/contest/560/problem/A 题面: A. Currency System in Geraldion time l ...
- 网页图表类框架(插件)——百度eCharts和Highcharts
ECharts, 缩写来自Enterprise Charts,商业级数据图表,一个纯Javascript的图表库, 可以流畅的运行在PC和移动设备上,兼容当前绝大部分浏览器(IE6/7/8/9 /10 ...
- 图像处理之全景拼接---基于sift的全景图像拼接
http://blog.csdn.net/masibuaa/article/details/9246493#comments
- [Python]xlrd 读取excel 日期类型2种方式
有个excle表格须要做一些过滤然后写入数据库中,可是日期类型的cell取出来是个数字,于是查询了下解决的办法. 主要的代码结构 data = xlrd.open_workbook(EXCEL_PAT ...
- jvmtop 监控
1 jar包 <!-- -JVMTOP监控- --> <dependency> <groupId>joda-time</groupId> <art ...
- opensearch空查询
query子句不支持为空的查询,可以使用filter子句:filter=area="" 或者 filter=filedlen(area)=0 可以使用相关性函数实现:https ...
- Html控件和Web控件(转)
作为一名ASP.NET的初学者,了解并且区别一些混淆概念是很必须的,今天这篇博文 就是主要向大家介绍一下Html控件和Web控件.在ASP.net中,用户界面控件主要就是 Html控件和Web控件,在 ...
- iOS与H5交互及UIWebView缓存
iOS原生App与H5页面交互笔记 最近在做一个项目用到了原生App与H5交互,之前有做过简单的H5页面直接调用原生方法的例子,就是利用UIWebView中的代理方法 //webview每次加载之前都 ...