[HNOI2011]括号修复
设\(nd[4]\)
0——多出来的右括号
1——多出来的左括号
2——取反后多出来的右括号
3——取反后多出来的左括号
这样一来
Swap: swap(0,3),swap(1,2),swap(sn[0],sn[1])
Invert: swap(0,2),swap(1,3),val[k]^=1
Replace: v<-siz[k],v+2^1<-siz[k],v^1<-0,v+2<-0
注意一下运算优先级就好
#include"cstdio"
#include"cstring"
#include"iostream"
#include"algorithm"
using namespace std;
const int MAXN=1e5+5;
int n,m,cnt,root;
char ch[MAXN];
int val[MAXN],rev[MAXN],sn[2][MAXN],siz[MAXN];
int nd[4][MAXN],tag3[MAXN];
bool tag1[MAXN],tag2[MAXN];
int cret(int v)
{
int tmp=++cnt;
siz[tmp]=1;
val[tmp]=v;
tag3[tmp]=-1;
nd[v][tmp]=nd[v+2^1][tmp]=1;
rev[tmp]=rand();
return tmp;
}
void pushdown(int k)
{
if(tag3[k]!=-1){
if(sn[0][k]) nd[tag3[k]][sn[0][k]]=nd[tag3[k]+2^1][sn[0][k]]=siz[sn[0][k]],nd[tag3[k]^1][sn[0][k]]=nd[tag3[k]+2][sn[0][k]]=0,val[sn[0][k]]=tag3[sn[0][k]]=tag3[k],tag1[sn[0][k]]=tag2[sn[0][k]]=0;
if(sn[1][k]) nd[tag3[k]][sn[1][k]]=nd[tag3[k]+2^1][sn[1][k]]=siz[sn[1][k]],nd[tag3[k]^1][sn[1][k]]=nd[tag3[k]+2][sn[1][k]]=0,val[sn[1][k]]=tag3[sn[1][k]]=tag3[k],tag1[sn[1][k]]=tag2[sn[1][k]]=0;
}if(tag2[k]){
swap(sn[0][k],sn[1][k]);
if(sn[0][k]) swap(nd[0][sn[0][k]],nd[3][sn[0][k]]),swap(nd[1][sn[0][k]],nd[2][sn[0][k]]),tag2[sn[0][k]]^=1;
if(sn[1][k]) swap(nd[0][sn[1][k]],nd[3][sn[1][k]]),swap(nd[1][sn[1][k]],nd[2][sn[1][k]]),tag2[sn[1][k]]^=1;
}if(tag1[k]){
if(sn[0][k]) swap(nd[0][sn[0][k]],nd[2][sn[0][k]]),swap(nd[1][sn[0][k]],nd[3][sn[0][k]]),tag1[sn[0][k]]^=1,val[sn[0][k]]^=1;
if(sn[1][k]) swap(nd[0][sn[1][k]],nd[2][sn[1][k]]),swap(nd[1][sn[1][k]],nd[3][sn[1][k]]),tag1[sn[1][k]]^=1,val[sn[1][k]]^=1;
}tag1[k]=tag2[k]=0;
tag3[k]=-1;
return;
}
void pushup(int k)
{
siz[k]=siz[sn[0][k]]+siz[sn[1][k]]+1;
nd[0][k]=nd[0][sn[0][k]];
nd[1][k]=nd[1][sn[1][k]];
int tmp=nd[1][sn[0][k]]-nd[0][sn[1][k]];
tmp+=val[k]?1:-1;
if(tmp>0) nd[1][k]+=tmp;
else nd[0][k]-=tmp;
nd[2][k]=nd[2][sn[0][k]];
nd[3][k]=nd[3][sn[1][k]];
tmp=nd[3][sn[0][k]]-nd[2][sn[1][k]];
tmp+=val[k]?-1:1;
if(tmp>0) nd[3][k]+=tmp;
else nd[2][k]-=tmp;
return;
}
void dro(int k,int v,int &x,int &y)
{
if(!k){x=y=0;return;}
pushdown(k);
if(siz[sn[0][k]]<v) x=k,dro(sn[1][k],v-siz[sn[0][k]]-1,sn[1][k],y);
else y=k,dro(sn[0][k],v,x,sn[0][k]);
pushup(k);
return;
}
int un(int x,int y)
{
if(!x||!y) return x|y;
if(rev[x]<rev[y]){
pushdown(x);
sn[1][x]=un(sn[1][x],y);
pushup(x);
return x;
}pushdown(y);
sn[0][y]=un(x,sn[0][y]);
pushup(y);
return y;
}
void slv0(int l,int r)
{
int x,y,z;
dro(root,r,x,z);
dro(x,l-1,x,y);
printf("%d\n",(nd[0][y]+1)/2+(nd[1][y]+1)/2);
root=un(un(x,y),z);
return;
}
void slv1(int l,int r)
{
int x,y,z;
dro(root,r,x,z);
dro(x,l-1,x,y);
tag1[y]^=1;val[y]^=1;
pushdown(y);pushup(y);
root=un(un(x,y),z);
return;
}
void slv2(int l,int r)
{
int x,y,z;
dro(root,r,x,z);
dro(x,l-1,x,y);
tag2[y]^=1;
pushdown(y);pushup(y);
root=un(un(x,y),z);
return;
}
void slv3(int l,int r,int kd)
{
int x,y,z;
dro(root,r,x,z);
dro(x,l-1,x,y);
tag3[y]=val[y]=kd;tag1[y]=tag2[y]=0;
pushdown(y);pushup(y);
root=un(un(x,y),z);
return;
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%s",ch+1);
for(int i=1;i<=n;++i) root=un(root,cret(ch[i]=='('));
while(m--){
int l,r;
scanf("%s%d%d",ch+1,&l,&r);
if(ch[1]=='Q') slv0(l,r);
else if(ch[1]=='I') slv1(l,r);
else if(ch[1]=='S') slv2(l,r);
else scanf("%s",ch+1),slv3(l,r,ch[1]=='(');
}return 0;
}
[HNOI2011]括号修复的更多相关文章
- 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]括号修复 只是多了一 ...
- bzoj千题计划222:bzoj2329: [HNOI2011]括号修复(fhq treap)
http://www.lydsy.com/JudgeOnline/problem.php?id=2329 需要改变的括号序列一定长这样 :)))((( 最少改变次数= 多余的‘)’/2 [上取整] + ...
- 【BZOJ2329/2209】[HNOI2011]括号修复/[Jsoi2011]括号序列 Splay
[BZOJ2329/2209][HNOI2011]括号修复/[Jsoi2011]括号序列 题解:我们的Splay每个节点维护如下东西:左边有多少多余的右括号,右边有多少多余的左括号,同时为了反转操作, ...
- BZOJ2329 [HNOI2011]括号修复
把左括号看做$1$,右括号看做$-1$,于是查询操作等于查询一个区间左边右边最大(最小)子段和 支持区间翻转,反转,覆盖操作...注意如果有覆盖操作,之前的操作全部作废了...于是在下传标记的时候要最 ...
- BZOJ 2329: [HNOI2011]括号修复 [splay 括号]
题目描述 一个合法的括号序列是这样定义的: 空串是合法的. 如果字符串 S 是合法的,则(S)也是合法的. 如果字符串 A 和 B 是合法的,则 AB 也是合法的. 现在给你一个长度为 N 的由‘(' ...
- BZOJ2329 HNOI2011 括号修复 splay+贪心
找平衡树练习题的时候发现了这道神题,可以说这道题是近几年单考splay的巅峰之作了. 题目大意:给出括号序列,实现区间翻转,区间反转和区间更改.查询区间最少要用几次才能改成合法序列. 分析: 首先我们 ...
- 2019.03.25 bzoj2329: [HNOI2011]括号修复(fhq_treap)
传送门 题意简述: 给一个括号序列,要求支持: 区间覆盖 区间取负 区间翻转 查询把一个区间改成合法括号序列最少改几位 思路: 先考虑静态的时候如何维护答案. 显然把所有合法的都删掉之后序列长这样: ...
- 【bzoj2329】[HNOI2011]括号修复 Splay
题目描述 题解 Splay 由于有区间反转操作,因此考虑Splay. 考虑答案:缩完括号序列后剩下的一定是 $a$ 个')'+ $b$ 个'(',容易发现答案等于 $\lceil\frac a2\rc ...
随机推荐
- wp推送消息笔记
最近想给应用添加推送消息,主要是toast消息,所以就打算去了解一下wp消息推送机制以及实现方法,过程中,查了许多资料,也遇到过一些问题,做完后,自己就做个小笔记,总结一下,好记性不如烂笔头嘛,以后可 ...
- 搭建json-server本地接口
这里我们来搭建一下json-server的本地接口,来让我们的网页能够对里面的数据进行增删改查 第一步,安装json-server的全局:Linux和windows在终端或者git中里面输入以下指令, ...
- 简单理解jQuery中$.getJSON、$.get、$.post、$.ajax用法
在WEB开发中异步请求方式普遍使用,ajax技术减少程序员的工作量,也提升用户交互体验.AJAX的四种异步请求方式都能实现基本需求,闲话不多说,直接切入正题. 1.$.getJSON $.getJSO ...
- 线程&线程控制
线程基本概念: 1 线程 (1)概念:linux下没有真正的线程,所谓的线程都是通过进程的pcb模拟的,因此linux下的线程也称为“轻量级进程”,之前我们所说的进程现在看来,可以理解为:只有一个线程 ...
- vue教程1-07 模板和过滤器
vue教程1-07 模板和过滤器 一.模板 {{msg}} 数据更新模板变化 {{*msg}} 数据只绑定一次 {{{msg}}} HTML转意输出 <!DOCTYPE html> < ...
- windows10升级系统后,无法远程桌面连接服务器
远程桌面,身份验证错误:要求的函数不正确等解决办法 https://www.cnblogs.com/LuckWJL/p/9018710.html
- Orleans实战目录
一 项目结构 1> 接口项目 .net core类库 2> Grains实现项目 .net core类库 3> 服务Host .net core console applicatio ...
- 利用VS2017跨平台远程调试aspnetcore应用
vs2017开始支持跨平台远程调试coreclr的应用,通常用于调试linux与mac上运行的aspnetcore程序,而如果运行在docker中的应用 要使用跨平台远程调试功能,首先运行corecl ...
- Python获取二维数组的行列数
import numpy as np x = np.array([[1,2,5],[2,3,5],[3,4,5],[2,3,6]]) # 输出数组的行和列数 print x.shape # (4, 3 ...
- Java实现二叉树先序,中序,后序,层次遍历
一.以下是我要解析的一个二叉树的模型形状.本文实现了以下方式的遍历: 1.用递归的方法实现了前序.中序.后序的遍历: 2.利用队列的方法实现层次遍历: 3.用堆栈的方法实现前序.中序.后序的遍历. . ...