洛谷 P3215 [HNOI2011]括号修复 / [JSOI2011]括号序列(fhq-treap)
题意:有一个长度为 \(n\) 的括号序列,你需要支持以下操作:
- 将 \([l,r]\) 中所有括号变为 \(c\)
- 将 \([l,r]\) 区间翻转
- 将 \([l,r]\) 区间中左括号变右括号,右括号变左括号
- 求最少需要改变多少个括号才能使得 \([l,r]\) 变成合法括号序列,保证区间长度为偶数。
\(1 \leq n \leq 10^5\)
基础的 fhq-treap 的题目,主要练下放标记的技巧。
首先我们需要将要求的东西转化为一个式子。例如括号序列 \((())))))((()\),将左右括号抵消掉之后就是 \())))((\),发现抵消完了之后变成了一段左括号跟一段右括号。
我们记 \((=-1\),\()=1\),假设前缀最大值为 \(mx\),后缀最小值为 \(mn\),那么最后会剩下 \(mx\) 个右括号和 \(-mn\) 个左括号,最少需要需要 \(\lceil \frac{mx}{2} \rceil+\lceil -\frac{mn}{2} \rceil\) 次操作。
我们建一棵平衡树,每个节点维护以下六个值:\(sz\) 子树大小,\(sum\) 子树权值和,\(prmn,prmx,sfmn,sfmx\) 表示前缀和后缀的最值,更新方式与最大子段和类似。
对于三个修改操作,我们考虑以下处理方式:
- 区间赋值,直接维护标记然后更新 \(sum\) 和 最值。
- 区间翻转操作,直接交换左右儿子和前、后缀最大最小值。
- 区间取逆操作,实际上就是将每个点的权值变为它的相反数,它的和、前后缀最大最小值也都变为了各自的相反数,如果有赋值标记,那么赋值标记也要取反。需要注意的一点是,最大值取了个相反数之后就变成了最小值,最小值取了相反数之后就变成了最大值,因此还需 swap 一下。
细节还是挺多的,代码也调了不少时间:
//Coded by tzc_wk
/*
数据不清空,爆零两行泪。
多测不读完,爆零两行泪。
边界不特判,爆零两行泪。
贪心不证明,爆零两行泪。
D P 顺序错,爆零两行泪。
大小少等号,爆零两行泪。
变量不统一,爆零两行泪。
越界不判断,爆零两行泪。
调试不注释,爆零两行泪。
溢出不 l l,爆零两行泪。
*/
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a) a.begin(),a.end()
#define giveup(...) return printf(__VA_ARGS__),0;
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,0x3f,sizeof(a))
#define fillsmall(a) memset(a,0xcf,sizeof(a))
#define mask(a) (1ll<<(a))
#define maskx(a,x) ((a)<<(x))
#define _bit(a,x) (((a)>>(x))&1)
#define _sz(a) ((int)(a).size())
#define filei(a) freopen(a,"r",stdin);
#define fileo(a) freopen(a,"w",stdout);
#define fileio(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#define put(x) putchar(x)
#define eoln put('\n')
#define space put(' ')
#define y1 y_chenxiaoyan_1
#define y0 y_chenxiaoyan_0
typedef pair<int,int> pii;
inline int read(){
int x=0,neg=1;char c=getchar();
while(!isdigit(c)){
if(c=='-') neg=-1;
c=getchar();
}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
return x*neg;
}
inline void print(int x){
if(x<0){
putchar('-');
print(abs(x));
return;
}
if(x<=9) putchar(x+'0');
else{
print(x/10);
putchar(x%10+'0');
}
}
inline int qpow(int x,int e,int _MOD){
int ans=1;
while(e){
if(e&1) ans=ans*x%_MOD;
x=x*x%_MOD;
e>>=1;
}
return ans;
}
int n=read(),m=read();
char str[100005];
struct node{
int ch[2],val,key;
int prmx,prmn,sfmx,sfmn,sum,sz;
int rv_lz,cov_lz,inv_lz;
} s[100005];
int ncnt=0,root;
inline void pushup(int k){
// s[0].prmx=s[0].sfmx=0;s[0].prmn=s[0].sfmn=0x3f3f3f3f;
s[k].prmx=max(s[s[k].ch[0]].prmx,s[s[k].ch[0]].sum+s[k].val+s[s[k].ch[1]].prmx);
s[k].prmn=min(s[s[k].ch[0]].prmn,s[s[k].ch[0]].sum+s[k].val+s[s[k].ch[1]].prmn);
s[k].sfmx=max(s[s[k].ch[1]].sfmx,s[s[k].ch[1]].sum+s[k].val+s[s[k].ch[0]].sfmx);
s[k].sfmn=min(s[s[k].ch[1]].sfmn,s[s[k].ch[1]].sum+s[k].val+s[s[k].ch[0]].sfmn);
s[k].sum=s[s[k].ch[0]].sum+s[s[k].ch[1]].sum+s[k].val;
s[k].sz=s[s[k].ch[0]].sz+s[s[k].ch[1]].sz+1;
}
inline void inv_part(int k){
s[k].val=-s[k].val;s[k].sum=-s[k].sum;
int prmn=s[k].prmn,prmx=s[k].prmx,sfmn=s[k].sfmn,sfmx=s[k].sfmx;
s[k].prmn=-prmx;s[k].prmx=-prmn;s[k].sfmn=-sfmx;s[k].sfmx=-sfmn;
s[k].cov_lz=-s[k].cov_lz;
s[k].inv_lz^=1;
}
inline void cov_part(int k,int mk){
s[k].val=mk;
s[k].sum=mk*s[k].sz;
s[k].cov_lz=mk;
if(mk==1){s[k].prmn=s[k].sfmn=0;s[k].prmx=s[k].sfmx=s[k].sum;}
else{s[k].prmx=s[k].sfmx=0;s[k].prmn=s[k].sfmn=s[k].sum;}
}
inline void rev_part(int k){
swap(s[k].ch[0],s[k].ch[1]);
swap(s[k].prmn,s[k].sfmn);
swap(s[k].prmx,s[k].sfmx);
s[k].rv_lz^=1;
}
inline void pushdown(int k){
if(s[k].inv_lz){
if(s[k].ch[0]) inv_part(s[k].ch[0]);
if(s[k].ch[1]) inv_part(s[k].ch[1]);
s[k].inv_lz=0;
}
if(s[k].cov_lz){
if(s[k].ch[0]) cov_part(s[k].ch[0],s[k].cov_lz);
if(s[k].ch[1]) cov_part(s[k].ch[1],s[k].cov_lz);
s[k].cov_lz=0;
}
if(s[k].rv_lz){
if(s[k].ch[0]) rev_part(s[k].ch[0]);
if(s[k].ch[1]) rev_part(s[k].ch[1]);
s[k].rv_lz=0;
}
}
inline int newnode(char c){
ncnt++;
s[ncnt].key=rand()<<15|rand();
s[ncnt].sz=1;
if(c=='('){
s[ncnt].prmn=s[ncnt].sfmn=-1;
s[ncnt].prmx=s[ncnt].sfmx=0;
s[ncnt].sum=-1;
s[ncnt].val=-1;
}
else{
s[ncnt].prmn=s[ncnt].sfmn=0;
s[ncnt].prmx=s[ncnt].sfmx=1;
s[ncnt].sum=1;
s[ncnt].val=1;
}
return ncnt;
}
inline void build(int &k,int l,int r){
int mid=(l+r)>>1;
k=newnode(str[mid]);
if(l!=mid) build(s[k].ch[0],l,mid-1);
if(r!=mid) build(s[k].ch[1],mid+1,r);
pushup(k);
}
inline void split(int k,int sz,int &a,int &b){
if(!k){
a=b=0;
return;
}
pushdown(k);
if(sz<=s[s[k].ch[0]].sz){
b=k;
split(s[k].ch[0],sz,a,s[k].ch[0]);
}
else{
a=k;
split(s[k].ch[1],sz-s[s[k].ch[0]].sz-1,s[k].ch[1],b);
}
pushup(k);
}
inline int merge(int a,int b){
pushdown(a);pushdown(b);
if(!a||!b) return a+b;
if(s[a].key<s[b].key){
s[a].ch[1]=merge(s[a].ch[1],b);
pushup(a);return a;
}
else{
s[b].ch[0]=merge(a,s[b].ch[0]);
pushup(b);return b;
}
}
inline void rev(int l,int r){
int k1,k2,k3;
split(root,l-1,k1,k2);
split(k2,r-l+1,k2,k3);
rev_part(k2);
root=merge(merge(k1,k2),k3);
}
inline void inv(int l,int r){
int k1,k2,k3;
split(root,l-1,k1,k2);
split(k2,r-l+1,k2,k3);
inv_part(k2);
root=merge(merge(k1,k2),k3);
}
inline void cov(int l,int r,int x){
int k1,k2,k3;
split(root,l-1,k1,k2);
split(k2,r-l+1,k2,k3);
cov_part(k2,x);
root=merge(merge(k1,k2),k3);
}
inline int getf(int x){
if(x&1) return (x>>1)+1;
else return x>>1;
}
inline int query(int l,int r){
int k1,k2,k3;
split(root,l-1,k1,k2);
split(k2,r-l+1,k2,k3);
int res=getf(s[k2].prmx)+getf(abs(s[k2].sfmn));
root=merge(merge(k1,k2),k3);
return res;
}
signed main(){
cin>>str+1;
build(root,1,n);
while(m--){
char opt[10];cin>>opt+1;
if(opt[1]=='R'){
int l=read(),r=read();
char c;cin>>c;
if(c=='(') cov(l,r,-1);
else cov(l,r,1);
}
if(opt[1]=='S'){
int l=read(),r=read();
rev(l,r);
}
if(opt[1]=='I'){
int l=read(),r=read();
inv(l,r);
}
if(opt[1]=='Q'){
int l=read(),r=read();
cout<<query(l,r)<<endl;
}
}
return 0;
}
洛谷 P3215 [HNOI2011]括号修复 / [JSOI2011]括号序列(fhq-treap)的更多相关文章
- 【BZOJ2329/2209】[HNOI2011]括号修复/[Jsoi2011]括号序列 Splay
[BZOJ2329/2209][HNOI2011]括号修复/[Jsoi2011]括号序列 题解:我们的Splay每个节点维护如下东西:左边有多少多余的右括号,右边有多少多余的左括号,同时为了反转操作, ...
- [HNOI2011]括号修复 / [JSOI2011]括号序列
传送门 Solution 一道题花费了两天的时间-- 在大佬@PinkRabbit的帮助下,终于AC了,感动-- 首先,我们考虑一个括号序列被修改成合法序列需要的次数: 我们需要修改的其实是形如... ...
- 洛谷P3369 【模板】普通平衡树(FHQ Treap)
题面 传送门 题解 写了一下\(FHQ\ Treap\) //minamoto #include<bits/stdc++.h> #define R register #define inl ...
- 洛谷 P3214 - [HNOI2011]卡农(线性 dp)
洛谷题面传送门 又是一道我不会的代码超短的题( 一开始想着用生成函数搞,结果怎么都搞不粗来/ll 首先不妨假设音阶之间存在顺序关系,最终答案除以 \(m!\) 即可. 本题个人认为一个比较亮的地方在于 ...
- BZOJ 2329: [HNOI2011]括号修复 [splay 括号]
题目描述 一个合法的括号序列是这样定义的: 空串是合法的. 如果字符串 S 是合法的,则(S)也是合法的. 如果字符串 A 和 B 是合法的,则 AB 也是合法的. 现在给你一个长度为 N 的由‘(' ...
- 洛谷P3205 [HNOI2011]合唱队 DP
原题链接点这里 今天在课上听到了这个题,听完后觉得对于一道\(DP\)题目来说,好的状态定义就意味着一切啊! 来看题: 题目描述 为了在即将到来的晚会上有更好的演出效果,作为AAA合唱队负责人的小A需 ...
- 洛谷P3216 [HNOI2011] 数学作业 [矩阵加速,数论]
题目传送门 数学作业 题目描述 小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题: 给定正整数 N和 M,要求计算 Concatenate (1 .. N)Mod M 的值,其中 C ...
- 洛谷 P3216 [HNOI2011]数学作业
最近学了矩阵,kzj大佬推荐了我这一道题目. 乍一眼看上去,没看出是矩阵,就随便打了一个暴力,30分. 然后仔细分析了一波,发现蛮简单的. 结果全wa了,先看看下面的错误分析吧! 首先,设f[n]为最 ...
- 洛谷P3211 [HNOI2011]XOR和路径(期望dp+高斯消元)
传送门 高斯消元还是一如既往的难打……板子都背不来……Kelin大佬太强啦 不知道大佬们是怎么发现可以按位考虑贡献,求出每一位是$1$的概率 然后设$f[u]$表示$u->n$的路径上这一位为$ ...
随机推荐
- 【UE4】 补丁Patch 与 DLC
概述 UE4 中主要使用 Project Launcher 来进行补丁和DLC的制作 补丁与 DLC 都需要基于某个版本而制作 补丁 与 DLC 最后以 Pak 形式表现, 补丁的 pak 可以重命名 ...
- kivy Label触发事件
kivy label也可以触发事件,为什么只有我这么无聊学垃圾kivy """ 在通过ref标记一段文本后点击这段文本就可以触发'on_ref_press'事件,在该事 ...
- hdu 1861 游船出租(模拟题,,水)
题意: 现有公园游船租赁处请你编写一个租船管理系统. 当游客租船时,管理员输入船号并按下S键,系统开始计时:当游客还船时,管理员输入船号并按下E键,系统结束计时. 船号为不超过100的正整数.当管理员 ...
- C++中gSOAP的使用
目录 SOAP简介 gSOAP 准备工作 头文件 构建客户端应用程序 生成soap源码 建立客户端项目 构建服务端应用程序 生成SOAP源码 建立服务端项目 打印报文 SOAP测试 项目源码 本文主要 ...
- Flink 的运行架构详细剖析
1. Flink 程序结构 Flink 程序的基本构建块是流和转换(请注意,Flink 的 DataSet API 中使用的 DataSet 也是内部流 ).从概念上讲,流是(可能永无止境的)数据记录 ...
- SSH 提示密码过期,如何通过 ansible 批量更新线上服务器密码
起因 线上环境是在内网,登陆线上环境需要使用 VPN + 堡垒机 登陆,但是我日常登陆线上环境都是 VPN + 堡垒机 + Socks5常驻代理,在shell端只需要保存会话,会话使用socks5代理 ...
- 微服务之十四如何在 Ocelot 网关中配置多实例 Swagger 访问
一.介绍 当我们开发基于微服务的应用程序的时候,有一个环节总是跳不过去的,那就是要创建 WebApi,然后,我们的应用程序基于 WebApi 接口去访问.在没有 Swagger 以前,我们开发好了 W ...
- SQL里ORDER BY 对查询的字段进行排序,字段为空不想排在最前
在安字段排序时 空字段往往都是在最前,我只是想空字段在排序的后面,不为空的在前,这个如何修改呢 order by datatime desc 这样的句子也一样 不管是正排还是倒排 为空的都在最 ...
- 用C++实现俄罗斯方块(Tetris)游戏
我是一个C++初学者,控制台实现了一个俄罗斯方块游戏. 代码如下: //"俄罗斯方块"V1.0 //李国良于2017年1月20日编写完成 #include <iostream ...
- 使用bs4中的方法爬取星巴克数据
import urllib.request # 请求url url = 'https://www.starbucks.com.cn/menu/' # 模拟浏览器发出请求 response = urll ...