2019.03.25 bzoj2329: [HNOI2011]括号修复(fhq_treap)
传送门
题意简述:
给一个括号序列,要求支持:
- 区间覆盖
- 区间取负
- 区间翻转
- 查询把一个区间改成合法括号序列最少改几位
思路:
先考虑静态的时候如何维护答案。
显然把所有合法的都删掉之后序列长这样:
))...)))(((...(())...)))(((...(())...)))(((...((
于是可以给(((赋值成−1-1−1,)))赋值成111,这样只用维护前缀最大值aaa和后缀最小值bbb。
然后就可以知道答案是⌊a+12⌋+⌊−b+12⌋\left\lfloor\frac{a+1}2\right\rfloor+\left\lfloor\frac{-b+1}2\right\rfloor⌊2a+1⌋+⌊2−b+1⌋,然后由于a+b=a+b=a+b=这段区间的和,因此实际上只用维护aaa。
于是用一个fhqtreapfhq_treapfhqtreap来支持上述修改即可。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define ri register int
#define gc getchar
using namespace std;
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
typedef pair<int,int> pii;
const int N=1e5+5;
int n,m;
char s[N];
inline unsigned int randd(){
static unsigned int x=23333;
return x^=x<<13,x^=x>>17,x^=x<<5;
}
namespace fhq{
#define lc son[p][0]
#define rc son[p][1]
int siz[N],son[N][2],rd[N],cov[N],ls[N],rs[N],sum[N],val[N],rt=0,tot=0;
bool rev[N],inv[N];
inline void pushup(int p){
ls[p]=max(ls[lc],sum[lc]+val[p]+ls[rc]);
rs[p]=max(rs[rc],sum[rc]+val[p]+rs[lc]);
siz[p]=siz[lc]+1+siz[rc];
sum[p]=sum[lc]+val[p]+sum[rc];
}
inline void pushcov(int p,int v){ls[p]=rs[p]=max((int)(inv[p]=rev[p]=0),sum[p]=((cov[p]=val[p]=v)*siz[p]));}
inline void pushrev(int p){rev[p]^=1,swap(ls[p],rs[p]),swap(lc,rc);}
inline void pushinv(int p){inv[p]^=1,ls[p]-=sum[p],rs[p]-=sum[p],swap(ls[p],rs[p]),val[p]=-val[p],sum[p]=-sum[p];}
inline void pushdown(int p){
if(cov[p])pushcov(lc,cov[p]),pushcov(rc,cov[p]),cov[p]=0;
if(rev[p])pushrev(lc),pushrev(rc),rev[p]=0;
if(inv[p])pushinv(lc),pushinv(rc),inv[p]=0;
}
inline int merge(int a,int b){
if(!a||!b)return a+b;
pushdown(a),pushdown(b);
if(rd[a]<rd[b])return son[a][1]=merge(son[a][1],b),pushup(a),a;
return son[b][0]=merge(a,son[b][0]),pushup(b),b;
}
inline pii split(int p,int k){
if(!p)return pii(0,0);
pii tmp;
pushdown(p);
if(siz[lc]>=k)return tmp=split(lc,k),lc=tmp.se,pushup(p),pii(tmp.fi,p);
return tmp=split(rc,k-siz[lc]-1),rc=tmp.fi,pushup(p),pii(p,tmp.se);
}
inline void build(int&p,int l,int r){
if(l>r)return;
int mid=l+r>>1;
p=++tot;
val[p]=sum[p]=s[mid]=='('?-1:1,rd[p]=randd();
if(l==r){ls[p]=rs[p]=max(0,val[p]),siz[p]=1;return;}
build(lc,l,mid-1),build(rc,mid+1,r),pushup(p);
}
inline void cover(int l,int r,int v){
pii x=split(rt,l-1),y=split(x.se,r-l+1);
pushcov(y.fi,v),rt=merge(x.fi,merge(y.fi,y.se));
}
inline void reverse(int l,int r){
pii x=split(rt,l-1),y=split(x.se,r-l+1);
pushrev(y.fi),rt=merge(x.fi,merge(y.fi,y.se));
}
inline void invert(int l,int r){
pii x=split(rt,l-1),y=split(x.se,r-l+1);
pushinv(y.fi),rt=merge(x.fi,merge(y.fi,y.se));
}
inline void query(int l,int r){
pii x=split(rt,l-1),y=split(x.se,r-l+1);
cout<<((ls[y.fi]+1)>>1)+((ls[y.fi]-sum[y.fi]+1)>>1)<<'\n',rt=merge(x.fi,merge(y.fi,y.se));
}
#undef lc
#undef rc
}
int main(){
n=read(),m=read(),scanf("%s",s+1);
fhq::build(fhq::rt,1,n);
char s[10],t[2];
for(ri l,r;m;--m){
scanf("%s",s),l=read(),r=read();
if(s[0]=='R'){
scanf("%s",t);
fhq::cover(l,r,t[0]=='('?-1:1);
}
if(s[0]=='Q')fhq::query(l,r);
if(s[0]=='I')fhq::invert(l,r);
if(s[0]=='S')fhq::reverse(l,r);
}
return 0;
}
2019.03.25 bzoj2329: [HNOI2011]括号修复(fhq_treap)的更多相关文章
- bzoj千题计划222:bzoj2329: [HNOI2011]括号修复(fhq treap)
http://www.lydsy.com/JudgeOnline/problem.php?id=2329 需要改变的括号序列一定长这样 :)))((( 最少改变次数= 多余的‘)’/2 [上取整] + ...
- BZOJ2329 [HNOI2011]括号修复
把左括号看做$1$,右括号看做$-1$,于是查询操作等于查询一个区间左边右边最大(最小)子段和 支持区间翻转,反转,覆盖操作...注意如果有覆盖操作,之前的操作全部作废了...于是在下传标记的时候要最 ...
- BZOJ2329 HNOI2011 括号修复 splay+贪心
找平衡树练习题的时候发现了这道神题,可以说这道题是近几年单考splay的巅峰之作了. 题目大意:给出括号序列,实现区间翻转,区间反转和区间更改.查询区间最少要用几次才能改成合法序列. 分析: 首先我们 ...
- 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]括号修复 只是多了一 ...
- [2019.03.25]Linux中的查找
TMUX天下第一 全世界所有用CLI Linux的人都应该用TMUX,我爱它! ======================== 以下是正文 ======================== Linu ...
- 【BZOJ2329】括号修复(Splay)
[BZOJ2329]括号修复(Splay) 题面 BZOJ 洛谷 题解 本来想着用线段树来写 但是有一个区间翻转 所以不能用线段树了,就只能用平衡树 然后直接\(Splay\)就好了 注意一下几个标记 ...
随机推荐
- nginx优化php-fpm优化 压力测试达到每分150万访问量webbench网站压力
webbench最多可以模拟3万个并发连接去测试网站的负载能力,个人感觉要比Apache自带的ab压力测试工具好,安装使用也特别方便. 1.适用系统:Linux 2.编译安装:引用wget http: ...
- vscode垂直选中列选中
VSCode列选择快捷键:Alt+Shift+左键
- MVC生成页码选择器返回HTML代码
我主要讲此代码用于MVC的分布页. 先看最终效果最终效果: 样式为bootstrap3中的分页“pagination”,如果不使用bootstrap单独提出来并不大 页码生成代码为: public s ...
- IDEA中显示RunDashboard
在打开.idea/workspace.xml,找到RunDashboard的配置,添加红色字体内容 <component name="RunDashboard"> &l ...
- Vue+DataTables warning:table id=xxxx -Cannot reinitialize DataTable.报错解决方法
问题描述: 使用DataTables来写列表,用vue来渲染数据,有搜索功能,每次点击搜索就会报错,如下图所示. 问题排查: 找了一系列原因,最后发现是我每次请求完数据之后都会添加分页功能,从而导致了 ...
- Game Engine Architecture 9
[Game Engine Architecture 9] 1.Formatted Output with OutputDebugString() int VDebugPrintF(const char ...
- 深入理解C++11【3】
[深入理解C++11[3]] 1.POD类型 Plain Old Data. Plain 表示 了POD是个普通的类型.C++11将POD划分为两个基本概念的合集: 1)平凡的(trivial) 2) ...
- c#遍历一个对象中所有的属性和值
SpDictItem sp = GetCFHObject.GetSpItem("); PropertyInfo[] propertys = sp.GetType().GetPropertie ...
- C语言作业04-数组
1.本章学习总结 1.1思维导图 1.2本章学习体会及代码量学习体会 1.2.1学习体会 通过本章的学习,学会了几种用于循环的语句,能够利用循环解决复杂的问题,但对于几种循环的使用并不熟练,其中对于c ...
- 区块链之Hyperledger(超级账本)Fabric v1.0 的环境搭建(更新)
参考链接:https://blog.csdn.net/so5418418/article/details/78355868 https://blog.csdn.net/wgh1015398431/ ...