[HNOI2011]括号修复 / [JSOI2011]括号序列
传送门
Solution
一道题花费了两天的时间……
在大佬
@PinkRabbit的帮助下,终于AC了,感动……首先,我们考虑一个括号序列被修改成合法序列需要的次数:
- 我们需要修改的其实是形如
...)))))(((((...- 我们把
(看成是-1,把)看成是1,那么其实只要知道了区间的前缀最大值pr和后缀最小值sum-pr那么就有$$ans=\left \lceil \frac{pr}{2} \right \rceil+\left \lceil \frac{-sum+su}{2} \right \rceil$$
如果我们维护了区间的前缀最大值
pr和后缀最大值su和区间和sum
- 区间翻转:
swap(pr,su)- 区间反转:
pr=-(sum-su)同时su=-(sum-pr),这里的(sum-su)就是前缀最小值,因为区间取了反,所以就是前缀最大值啦- 区间覆盖:直接打标记
所有区间操作都可以用平衡树来实现
要注意:区间覆盖的优先级应大于另外两个操作
Code
#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
#define MN 100005
char s[MN];
class fhq
{
private:
int sz;
int pri[MN],ls[MN],rs[MN],siz[MN];
int pr[MN],su[MN],tt[MN],cover[MN],V[MN];
bool rev[MN],inv[MN];
inline unsigned int random()
{
static unsigned int x=23333;
return x^=x<<13,x^=x>>17,x^=x<<5;
}
inline void up(int x)
{
siz[x]=1+siz[ls[x]]+siz[rs[x]];
tt[x]=tt[ls[x]]+tt[rs[x]]+V[x];
pr[x]=max(pr[ls[x]],tt[ls[x]]+V[x]+pr[rs[x]]);
su[x]=max(su[rs[x]],tt[rs[x]]+V[x]+su[ls[x]]);
}
inline void update(int x,int opt)
{
if(!x) return;
if(opt==1)
{
std::swap(pr[x],su[x]);std::swap(ls[x],rs[x]);
rev[ls[x]]^=1;rev[rs[x]]^=1;
}
if(opt==2)
{
V[x]=-V[x];
pr[x]=-(tt[x]-pr[x]);su[x]=-(tt[x]-su[x]);
std::swap(pr[x],su[x]);
tt[x]=-tt[x];
inv[ls[x]]^=1;inv[rs[x]]^=1;
}
if(opt==3)
{
V[x]=cover[x];tt[x]=cover[x]*siz[x];
su[x]=max(0,tt[x]);pr[x]=max(0,tt[x]);
cover[ls[x]]=cover[rs[x]]=cover[x];
rev[ls[x]]=inv[ls[x]]=0;
rev[rs[x]]=inv[rs[x]]=0;
}
}
inline void down(int x)
{
if(cover[x]) update(ls[x],3),update(rs[x],3),cover[x]=0;
if(rev[x]) update(ls[x],1),update(rs[x],1),rev[x]=0;
if(inv[x]) update(ls[x],2),update(rs[x],2),inv[x]=0;
}
public:
int rt;
int Merge(int rt1,int rt2)
{
if(!rt1||!rt2) return rt2|rt1;
if(pri[rt1]<pri[rt2])
{
down(rt1),rs[rt1]=Merge(rs[rt1],rt2);
up(rt1);return rt1;
}
else
{
down(rt2),ls[rt2]=Merge(rt1,ls[rt2]);
up(rt2);return rt2;
}
}
void Split(int x,int k,int&rt1,int&rt2)
{
if(!x) return (void)(rt1=rt2=0);
down(x);
if(k<=siz[ls[x]])
{
Split(ls[x],k,rt1,rt2);
ls[x]=rt2;up(x);rt2=x;
}
else
{
Split(rs[x],k-siz[ls[x]]-1,rt1,rt2);
rs[x]=rt1;up(x);rt1=x;
}
}
void Build(int &x,int l,int r)
{
if(l>r) return;int mid=l+r>>1;
x=++sz;
V[x]=tt[x]=(s[mid]==')'?1:-1),pri[x]=random();
if(l==r) return(void)(pr[x]=su[x]=max(0,V[x]),siz[x]=1);
Build(ls[x],l,mid-1),Build(rs[x],mid+1,r);up(x);
}
void Reverse(int l,int r)
{
register int rt1,rt2,rt3,rt4;
Split(rt,l-1,rt1,rt2);Split(rt2,r-l+1,rt3,rt4);
rev[rt3]^=1;update(rt3,1);rt=Merge(rt1,Merge(rt3,rt4));
}
void Invert(int l,int r)
{
register int rt1,rt2,rt3,rt4;
Split(rt,l-1,rt1,rt2);Split(rt2,r-l+1,rt3,rt4);
inv[rt3]^=1;update(rt3,2);rt=Merge(rt1,Merge(rt3,rt4));
}
void Replace(int l,int r,int c)
{
register int rt1,rt2,rt3,rt4;
Split(rt,l-1,rt1,rt2);Split(rt2,r-l+1,rt3,rt4);
cover[rt3]=c,update(rt3,3);rev[rt3]=inv[rt3]=0;rt=Merge(rt1,Merge(rt3,rt4));
}
int Query(int l,int r)
{
register int rt1,rt2,rt3,rt4,ret;
Split(rt,l-1,rt1,rt2);
Split(rt2,r-l+1,rt3,rt4);
ret=(pr[rt3]+1)/2+(-tt[rt3]+pr[rt3]+1)/2;
rt=Merge(rt1,Merge(rt3,rt4));
return ret;
}
}T;
int main(){
register int n,m,l,r;
n=read(),m=read();
scanf("%s",s+1);T.Build(T.rt,1,n);
register char opt[10],c[2];
while(m--)
{
scanf("%s",opt+1);l=read(),r=read();
if(opt[1]=='R') scanf("%s",c),T.Replace(l,r,c[0]=='('?-1:1);
if(opt[1]=='S') T.Reverse(l,r);
if(opt[1]=='I') T.Invert(l,r);
if(opt[1]=='Q') printf("%d\n",T.Query(l,r));
}
return 0;
}
Blog来自PaperCloud,未经允许,请勿转载,TKS!
[HNOI2011]括号修复 / [JSOI2011]括号序列的更多相关文章
- 【BZOJ2329/2209】[HNOI2011]括号修复/[Jsoi2011]括号序列 Splay
[BZOJ2329/2209][HNOI2011]括号修复/[Jsoi2011]括号序列 题解:我们的Splay每个节点维护如下东西:左边有多少多余的右括号,右边有多少多余的左括号,同时为了反转操作, ...
- 洛谷 P3215 [HNOI2011]括号修复 / [JSOI2011]括号序列(fhq-treap)
题目链接 题意:有一个长度为 \(n\) 的括号序列,你需要支持以下操作: 将 \([l,r]\) 中所有括号变为 \(c\) 将 \([l,r]\) 区间翻转 将 \([l,r]\) 区间中左括号变 ...
- BZOJ 2329: [HNOI2011]括号修复 [splay 括号]
题目描述 一个合法的括号序列是这样定义的: 空串是合法的. 如果字符串 S 是合法的,则(S)也是合法的. 如果字符串 A 和 B 是合法的,则 AB 也是合法的. 现在给你一个长度为 N 的由‘(' ...
- BZOJ 2329: [HNOI2011]括号修复( splay )
把括号序列后一定是))))((((这种形式的..所以维护一个最大前缀和l, 最大后缀和r就可以了..答案就是(l+1)/2+(r+1)/2...用splay维护,O(NlogN). 其实还是挺好写的, ...
- bzoj千题计划222:bzoj2329: [HNOI2011]括号修复(fhq treap)
http://www.lydsy.com/JudgeOnline/problem.php?id=2329 需要改变的括号序列一定长这样 :)))((( 最少改变次数= 多余的‘)’/2 [上取整] + ...
- 【BZOJ-2329&2209】括号修复&括号序列 Splay
2329: [HNOI2011]括号修复 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 1007 Solved: 476[Submit][Statu ...
- bzoj 2209: [Jsoi2011]括号序列 splay
2209: [Jsoi2011]括号序列 Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 833 Solved: 392[Submit][Status ...
- BZOJ 2209: [Jsoi2011]括号序列 [splay 括号]
2209: [Jsoi2011]括号序列 Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 1111 Solved: 541[Submit][Statu ...
- bzoj 2209 [Jsoi2011]括号序列 平衡树
2209: [Jsoi2011]括号序列 Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 1404 Solved: 699[Submit][Statu ...
随机推荐
- javascript:void(0);的含义以及使用场景
一.含义: javascript:是伪协议,表示内容通过javascript执行. void(0)表示不作任何操作. 二.使用场景 1.href=”javascript:void(0);” 作用:为了 ...
- 多线程使用libcurl
curl默认情况下有两个地方是线程不安全的, 需要特殊处理, 1是curl_global_init 这个函数必须单线程调用, 2是默认多线程调用https会莫名其妙的挂掉, 以下是网上的解决方案 ht ...
- wepy框架 怎么在template模板中使用函数
呵呵.介绍说是类似vue,用起来真累人,就想在模板中使用个函数都要查N久的文档才知道. 具体要怎么操作呢? 要先创建个wxs脚本文件,在里面定义函数或其它的,然后在页面或组件中引入这文件,就可以在模板 ...
- vue多页面项目搭建(vue-cli 4.0)
1.创建vue项目 cmd命令执行 vue create app (app 自定义的项目名) 一般都会选择后者,自己配置一下自己需要的选项(空格为选中) 这是我个人需要的一些选项,路由Router.状 ...
- HTML中的图片标签的用法!
在HTML中<img>这个标签是定义文本中的图片标签,它的作用就比如说可以提供图片的名字.提供图片的尺寸大小和提供图片的一些图片属性,比如Alt这个属性,可以给图片一个名称来告诉朋友们.这 ...
- win10 系统解决mysql中文乱码问题
问题: 向mysql 数据库插入数据是,出现中文乱码(中文均显示为‘??’) 原因: mysql 默认的字符集是latin1,所以我么需要改为ut8编码才可以 解决: 1.以管理员权限运行cmd窗口 ...
- Redis其他数据结构
用户日活月活怎么统计 - Redis HyperLogLog 详解 HyperLogLog 提出问题 我们先思考一个常见的业务问题:如果你负责开发维护一个大型的网站,有一天老板找产品经理要网站每个网页 ...
- JavaIO模型--装饰者模式
JavaIO体现出装饰者的设计模式 今天在学SparkRDD之前,听了一堂复习JavaIO的课,觉得讲得不错 Java的IO一直让我觉得一层一层的很麻烦,刚接触的时候,理不太清楚 只知道要分解为输入输 ...
- k8s的pod
一.Pod的分类 自主式Pod : 控制器管理的Pod:Kubernetes使用更高级的称为Controller的抽象层,来管理Pod实例.每个Pod都有一个特殊的被称为“根容器”的Pause容器. ...
- MySQL查询去重
方法一: distinct select count(distinct CName) from Course 方法二: 使用分组 group by select count(1) from Cours ...