2329: [HNOI2011]括号修复

Time Limit: 40 Sec  Memory Limit: 128 MB
Submit: 1007  Solved: 476
[Submit][Status][Discuss]

Description

Input

Output

Sample Input

Sample Output

HINT

Source

Solution

一眼Splay么....关键是怎么维护...

一开始看错题了...想了很久歪路,其实想一下还是可以想到的么..

对于一个括号序列,首先合法的括号对是对询问答案没有贡献的,所以可以忽略,剩余的括号序列必然是形如$)*(*$的序列。

所以答案显然就是$\lfloor \frac{Num_{)}+1}{2} \rfloor + \lfloor \frac{Num{(}+1}{2} \rfloor$。

然后只需要Splay中维护左右起最大连续$($左右起最大连续$)$,即可得到答案。

考虑怎么维护这样的东西..括号序列一种最典型的表示方式可以认为是$+1-1$,这里也一样啊,不妨令$(=-1$,$)=+1$

这样就可以以一种类似最大最小连续子段和的方式去维护上述量了。

然后就是修改操作。

覆盖操作显然会清空翻转操作和取反操作,问题在于取反操作和覆盖操作的下放顺序会对结果有影响!!!(画图考虑一下)

所以值得注意的就是,在下放标记的时候,取反标记同样会使覆盖标记发生取反。(再画图考虑一下)

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
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*10+ch-'0'; ch=getchar();}
return x*f;
}
#define MAXN 100010
#define INF 0x3fffffff
int N,M;
char s[MAXN]; namespace SplayTree{
#define lson(x) son[x][0]
#define rson(x) son[x][1]
int son[MAXN][2],fa[MAXN],root,sz;
int lmin[MAXN],rmin[MAXN],lmax[MAXN],rmax[MAXN],size[MAXN],sum[MAXN],val[MAXN];
int rev[MAXN],inv[MAXN],cov[MAXN];
inline void Newnode(int &x,int last,int v)
{
x=++sz;
size[x]=1;
val[x]=sum[x]=v;
if (v==1)
lmin[x]=rmin[x]=0,lmax[x]=rmax[x]=v;
else
lmin[x]=rmin[x]=v,lmax[x]=rmax[x]=0;
fa[x]=last; son[x][0]=son[x][1]=0;
}
inline int Right(int x) {return son[fa[x]][1]==x;}
inline void Update(int x)
{
if (!x) return;
sum[x]=sum[lson(x)]+sum[rson(x)]+val[x];
size[x]=size[lson(x)]+size[rson(x)]+1;
lmax[x]=max(lmax[lson(x)],sum[lson(x)]+val[x]+lmax[rson(x)]);
rmax[x]=max(rmax[rson(x)],sum[rson(x)]+val[x]+rmax[lson(x)]);
lmin[x]=min(lmin[lson(x)],sum[lson(x)]+val[x]+lmin[rson(x)]);
rmin[x]=min(rmin[rson(x)],sum[rson(x)]+val[x]+rmin[lson(x)]);
}
inline void Rev(int x)
{
if (!x) return;
rev[x]^=1;
swap(son[x][0],son[x][1]);
swap(lmax[x],rmax[x]),swap(lmin[x],rmin[x]);
}
inline void Cov(int x,int d)
{
if (!x) return;
cov[x]=d; rev[x]=0; inv[x]=0;
sum[x]=d*size[x]; val[x]=d;
if (d==1)
lmax[x]=rmax[x]=size[x],lmin[x]=rmin[x]=0;
else
lmax[x]=rmax[x]=0,lmin[x]=rmin[x]=-size[x];
}
inline void Inv(int x)
{
if (!x) return;
inv[x]^=1;
sum[x]=-sum[x]; val[x]=-val[x];
swap(lmax[x],lmin[x]),swap(rmax[x],rmin[x]);
lmax[x]=-lmax[x],rmax[x]=-rmax[x];
lmin[x]=-lmin[x],rmin[x]=-rmin[x];
cov[x]=-cov[x];
}
inline void Pushdown(int x)
{
if (rev[x]!=0)
Rev(son[x][0]),Rev(son[x][1]),rev[x]^=1;
if (inv[x]!=0)
Inv(son[x][0]),Inv(son[x][1]),inv[x]^=1;
if (cov[x]!=0)
Cov(son[x][0],cov[x]),Cov(son[x][1],cov[x]),cov[x]=0;
}
inline int Build(int l,int r,int last)
{
int mid=(l+r)>>1,x;
Newnode(x,last,s[mid]=='('? -1:1);
if (mid-1>=l) son[x][0]=Build(l,mid-1,x);
if (mid+1<=r) son[x][1]=Build(mid+1,r,x);
Update(x);
return x;
}
inline void Rotate(int x)
{
int y=fa[x],z=fa[y],w=Right(x);
Pushdown(y); Pushdown(x);
son[y][w]=son[x][w^1]; fa[son[y][w]]=y;
fa[y]=x; son[x][w^1]=y; fa[x]=z;
if (z) son[z][son[z][1]==y]=x;
Update(y); Update(x);
}
inline void Splay(int x,int tar)
{
for (int y; (y=fa[x])!=tar; Rotate(x))
if (fa[y]!=tar) Rotate(Right(x)==Right(y) ? y:x);
if (!tar) root=x;
}
inline int Find(int x,int k)
{
Pushdown(x);
if (size[son[x][0]]>=k) return Find(son[x][0],k);
if (size[son[x][0]]+1==k) return x;
return Find(son[x][1],k-size[son[x][0]]-1);
}
inline int Split(int l,int r)
{
int x=Find(root,l),y=Find(root,r+2);
Splay(x,0); Splay(y,root); return lson(rson(root));
}
inline void Cover(int l,int r,int d) {int x=Split(l,r); Cov(x,d);}
inline void Rever(int l,int r) {int x=Split(l,r); Rev(x);}
inline void Inver(int l,int r) {int x=Split(l,r); Inv(x);}
inline int Query(int l,int r) {int x=Split(l,r); return (lmax[x]+1)/2+(-rmin[x]+1)/2;}
}using namespace SplayTree; int main()
{
Newnode(root,0,0);
Newnode(son[root][1],root,0); N=read(),M=read();
scanf("%s",s+1); son[son[root][1]][0]=SplayTree::Build(1,N,son[root][1]); while (M--) {
char opt[10]; scanf("%s",opt+1);
int l=read(),r=read();
switch (opt[1]) {
case 'R' : scanf("%s",s+1); SplayTree::Cover(l,r,s[1]=='('? -1:1); break;
case 'Q' : printf("%d\n",SplayTree::Query(l,r)); break;
case 'S' : SplayTree::Rever(l,r); break;
case 'I' : SplayTree::Inver(l,r); break;
}
} return 0;
}

大过年的,写啥Splay啊....这道题又捯饬了两个多小时...真是自虐。

【BZOJ-2329&2209】括号修复&括号序列 Splay的更多相关文章

  1. BZOJ 2329/2209 [HNOI2011]括号修复 (splay)

    题目大意: 让你维护一个括号序列,支持 1.区间修改为同一种括号 2.区间内所有括号都反转 3.翻转整个区间,括号的方向不变 4.查询把某段区间变为合法的括号序列,至少需要修改多少次括号 给跪了,足足 ...

  2. BZOJ 2329: [HNOI2011]括号修复( splay )

    把括号序列后一定是))))((((这种形式的..所以维护一个最大前缀和l, 最大后缀和r就可以了..答案就是(l+1)/2+(r+1)/2...用splay维护,O(NlogN). 其实还是挺好写的, ...

  3. 【BZOJ2329/2209】[HNOI2011]括号修复/[Jsoi2011]括号序列 Splay

    [BZOJ2329/2209][HNOI2011]括号修复/[Jsoi2011]括号序列 题解:我们的Splay每个节点维护如下东西:左边有多少多余的右括号,右边有多少多余的左括号,同时为了反转操作, ...

  4. ●BZOJ 2329 [HNOI2011]括号修复.cpp

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2329 题解: Splay 类似 BZOJ 2329 [HNOI2011]括号修复 只是多了一 ...

  5. bzoj千题计划222:bzoj2329: [HNOI2011]括号修复(fhq treap)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2329 需要改变的括号序列一定长这样 :)))((( 最少改变次数= 多余的‘)’/2 [上取整] + ...

  6. 【BZOJ2329】括号修复(Splay)

    [BZOJ2329]括号修复(Splay) 题面 BZOJ 洛谷 题解 本来想着用线段树来写 但是有一个区间翻转 所以不能用线段树了,就只能用平衡树 然后直接\(Splay\)就好了 注意一下几个标记 ...

  7. BZOJ2329:[HNOI2011]括号修复

    浅谈\(splay\):https://www.cnblogs.com/AKMer/p/9979592.html 浅谈\(fhq\)_\(treap\):https://www.cnblogs.com ...

  8. 【BZOJ】2209: [Jsoi2011]括号序列(splay)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2209 splay又犯逗........upd1那里的sum忘记赋值反............. 本题 ...

  9. bzoj 2209: [Jsoi2011]括号序列 splay

    2209: [Jsoi2011]括号序列 Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 833  Solved: 392[Submit][Status ...

随机推荐

  1. JAVA记录-Servlet RequestDispatcher请求转发

    RequestDispatcher接口提供将请求转发送到另一个资源的功能,它可能是html,servlet或jsp等. 此接口也可用于包括另一资源的内容.它是servlet协作的一种方式. 在Requ ...

  2. SQL记录-PLSQL日期与时间

    PL/SQL日期及时间 PL/SQL提供两个日期和时间相关的数据类型: 日期时间(Datetime)数据类型 间隔数据类型 datetime数据类型有: DATE TIMESTAMP TIMESTAM ...

  3. 51nod 1258 序列求和 V4

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1258 1258 序列求和 V4  基准时间限制:8 秒 空间限制:131 ...

  4. chrome 隐藏技能之 base64 图片转换

    有时候我们要转换图片为base64,或者将base64转回图片,可能都需要找一些在线工具或者软件类型的工具才行.当然 chrome 也算是软件,但是好在做前端的都有 chrome.好了,来看下简单的例 ...

  5. 本日吐槽!“人傻钱多”的P2P公司是否是程序员的合适选择(群聊天记录的娱乐)

    这个题目“P2P的职位是否是程序员的合适选择”这个问题本身是没啥可以吐槽的 但是每当我们讨论那种类型的公司工资愿意给前端工程师开的最高的时候,P2P这个行业被第一个提出了 目前我收到过面试的企业类型千 ...

  6. asp.net分页之AJAX 分页

    查询功能是开发中最重要的一个功能,大量数据的显示,我们用的最多的就是分页. 在ASP.NET 中有很多数据展现的控件,比如Repeater.GridView,用的最多的GridView,它同时也自带了 ...

  7. Informatica学习:3、用户创建与权限管理

    环境:win7 下安装Informatica 9.6.1 服务器端与客户端作为学习之用,Linux大同小异 一.用户创建(服务器端) 1.登陆admin console (1)打开Admin Cons ...

  8. windows下nodejs服务器的安装与配置

    1下载安装 download from the link: https://nodejs.org/en/ windows下的安装直接运行exe,略过-- 注:由于用户权限的问题,最好将nodejs安装 ...

  9. 『记录』Android参考资料

    欢迎留言推荐好的教程.资料.博客及作者等. 『记录』Android参考资料 1.前期环境 Android Studio使用Git Android Studio快捷键总结 Android Studio及 ...

  10. 浅谈js设计模式 — 享元模式

    享元(flyweight)模式是一种用于性能优化的模式,“fly”在这里是苍蝇的意思,意为蝇量级.享元模式的核心是运用共享技术来有效支持大量细粒度的对象. 假设有个内衣工厂,目前的产品有 50种男式内 ...