BZOJ 2329/2209 [HNOI2011]括号修复 (splay)
题目大意:
让你维护一个括号序列,支持
1.区间修改为同一种括号
2.区间内所有括号都反转
3.翻转整个区间,括号的方向不变
4.查询把某段区间变为合法的括号序列,至少需要修改多少次括号
给跪了,足足$de$了$3h$
感觉这道题的思维难度比维修数列高多了
前三个操作都非常好搞,都是区间打标记
注意下推标记的顺序,子树根如果有区间覆盖标记,那么子树内所有节点的反转和翻转标记都失效了,要清空
而下传到同一节点的区间覆盖和反转翻转标记不冲突
我们下推标记时必须保证,下推后,两个子节点的状态拿来就能用,不用再进行额外的修改
第四个操作,可以像维修数列那道题一样维护一个小$dp$,只不过这个$dp$更为复杂
定义$f[x][0/1][0/1]$表示节点$x$表示的子树,左/右边剩余的左/右括号数量
左边和右边表示的不是左右子树!
状态 左边右括号01 和 右边左括号10 表示x子树的括号序列,正匹配‘()’时,左边剩余的右括号和右边剩余的左括号一定不能被匹配,记录它们的数量
状态 左边左括号00 和 右边右括号11 表示x子树的括号序列,反匹配‘)(’时,左边剩余的左括号和右边剩余的右括号一定不能被匹配,记录它们的数量
转移就很显然了
void pushup(int x)
{
int ls=ch[x][],rs=ch[x][],w=val[x]?:-;
f[x][][]=f[ls][][]+max(,f[rs][][]-w-f[ls][][]);
f[x][][]=f[ls][][]+max(,f[rs][][]+w-f[ls][][]);
f[x][][]=f[rs][][]+max(,f[ls][][]-w-f[rs][][]);
f[x][][]=f[rs][][]+max(,f[ls][][]+w-f[rs][][]);
sz[x]=sz[ls]+sz[rs]+;
}
而 覆盖/翻转/反转 操作同样需要修改dp,打表找规律可得
void Rpl(int x,int w) //覆盖
{
memset(f[x],,sizeof(f[x]));
f[x][w^][w]=f[x][w][w]=sz[x]; //不论反匹配还是正匹配,肯定全都不能被匹配上
val[x]=w, tag[x]=, rev[x]=, inv[x]=; //去除反转翻转标记,否则可能会下传相反的覆盖标记
}
void Rev(int x) //翻转,把序列翻转
{
swap(f[x][][],f[x][][]); //反匹配变为正匹配,括号的位置改变,左右数量交换
swap(f[x][][],f[x][][]);
swap(ch[x][],ch[x][]); rev[x]^=;
}
void Inv(int x) //反转,左括号变右括号
{
swap(f[x][][],f[x][][]); //反匹配变为正匹配,括号的位置不变,左右数量不变
swap(f[x][][],f[x][][]);
val[x]^=; inv[x]^=;
}
剩下就是常规的$splay$了
此外,一定要在$find$函数里下推标记,否则会找到错误的位置!
千万千万不要打错变量名,我有足足1h30min浪费在了打错的变量名上了..
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 101000
#define M1 2010
#define S1 (N1<<1)
#define T1 (N1<<2)
#define ll long long
#define uint unsigned int
#define rint register int
#define dd double
#define il inline
#define inf 233333333
using namespace std; int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*fh;
}
int n,m;
int a[N1];
char str[N1];
struct Splay{
#define root ch[0][1]
int ch[N1][],fa[N1],tag[N1],val[N1],rev[N1],inv[N1],sz[N1],f[N1][][];
int idf(int x){return ch[fa[x]][]==x?:;}
void Rpl(int x,int w)
{
memset(f[x],,sizeof(f[x]));
f[x][w^][w]=f[x][w][w]=sz[x];
val[x]=w, tag[x]=, rev[x]=, inv[x]=;
}
void Rev(int x)
{
swap(f[x][][],f[x][][]);
swap(f[x][][],f[x][][]);
swap(ch[x][],ch[x][]); rev[x]^=;
}
void Inv(int x) //左括号变有括号。
{
swap(f[x][][],f[x][][]);
swap(f[x][][],f[x][][]);
val[x]^=; inv[x]^=;
}
void pushdown(int x)
{
int ls=ch[x][],rs=ch[x][];
if(tag[x])
{
if(ls) Rpl(ls,val[x]);
if(rs) Rpl(rs,val[x]);
inv[x]=rev[x]=tag[x]=; return;
}
if(rev[x])
{
if(ls) Rev(ls);
if(rs) Rev(rs);
rev[x]^=;
}
if(inv[x])
{
if(ls) Inv(ls);
if(rs) Inv(rs);
inv[x]^=;
}
}
void pushup(int x)
{
int ls=ch[x][],rs=ch[x][],w=val[x]?:-;
f[x][][]=f[ls][][]+max(,f[rs][][]-w-f[ls][][]);
f[x][][]=f[ls][][]+max(,f[rs][][]+w-f[ls][][]);
f[x][][]=f[rs][][]+max(,f[ls][][]-w-f[rs][][]);
f[x][][]=f[rs][][]+max(,f[ls][][]+w-f[rs][][]);
sz[x]=sz[ls]+sz[rs]+;
}
void rot(int x)
{
int y=fa[x],ff=fa[y],px=idf(x),py=idf(y);
fa[ch[x][px^]]=y,ch[y][px]=ch[x][px^];
ch[x][px^]=y,fa[y]=x,ch[ff][py]=x,fa[x]=ff;
pushup(y),pushup(x);
}
//int stk[N1],tp;
void splay(int x,int to)
{
int y=x; to=fa[to];
while(fa[x]!=to)
{
y=fa[x];
if(fa[y]==to) rot(x);
else if(idf(y)==idf(x)) rot(y),rot(x);
else rot(x),rot(x);
}
/*stk[++tp]=x;
while(fa[y]){stk[++tp]=fa[y],y=fa[y];}
while(tp){pushdown(stk[tp--]);}*/
}
int build(int l,int r,int ff)
{
if(l>r) return ;
int mid=(l+r)>>,x=mid+;
val[x]=a[mid];fa[x]=ff;
ch[x][]=build(l,mid-,x);
ch[x][]=build(mid+,r,x);
pushup(x);
return x;
}
int find(int K)
{
int x=root;
while()
{
pushdown(x);
if(K>sz[ch[x][]]){
K-=sz[ch[x][]];
if(K==) {pushdown(x);return x;}
K--; x=ch[x][];
}else{
x=ch[x][];
}
}
}
int split(int l,int r)
{
int x=find(l); splay(x,root);
int y=find(r+); splay(y,ch[x][]);
return ch[y][];
}
void Replace(int l,int r,int w)
{
int x=split(l,r);
val[x]=w; tag[x]=; rev[x]=inv[x]=;
memset(f[x],,sizeof(f[x]));
f[x][w^][w]=f[x][w][w]=sz[x];
}
void Swp(int l,int r)
{
int x=split(l,r);
Rev(x);
}
void Invert(int l,int r)
{
int x=split(l,r), ls=ch[x][], rs=ch[x][];
swap(f[x][][],f[x][][]), swap(f[x][][],f[x][][]);
val[x]^=; inv[x]^=; //val[ls]^=1; val[rs]^=1;
}
int Query(int l,int r)
{
int x=split(l,r);
return f[x][][]/+((f[x][][]&)?:)+f[x][][]/+((f[x][][]&)?:);
}
void debug()
{
for(int i=;i<=n+;i++)
printf("%c",val[i]?')':'(');
puts("");
}
#undef root
}s; int main()
{
//freopen("t2.in","r",stdin);
scanf("%d%d",&n,&m);
int i,j,x,y,w;
scanf("%s",str+);
for(i=;i<=n;i++) a[i]=(str[i]=='(')?:;
a[]=,a[n+]=;
s.ch[][]=s.build(,n+,);
for(i=;i<=m;i++)
{
scanf("%s",str);
if(str[]=='R'){
x=gint(), y=gint(), scanf("%s",str);
w=(str[]=='(')?:;
s.Replace(x,y,w);
}else if(str[]=='S'){
x=gint(), y=gint();
s.Swp(x,y);
}else if(str[]=='I'){
x=gint(), y=gint();
s.Invert(x,y);
}else if(str[]=='Q'){
x=gint(), y=gint();
printf("%d\n",s.Query(x,y));
}
//s.debug();
}
return ;
}
附赠对拍程序以及数据生成器,建议自己写,考场上这种题不拍简直找死
暴力:
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 1010
#define M1 2010
#define S1 (N1<<1)
#define T1 (N1<<2)
#define ll long long
#define uint unsigned int
#define rint register int
#define dd double
#define il inline
#define inf 233333333
using namespace std; int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*fh;
}
int n,m;
int a[N1],tmp[N1];
char str[N1]; void debug()
{
for(int i=;i<=n;i++)
printf("%c",a[i]?')':'(');
puts("");
} int main()
{
freopen("t2.in","r",stdin);
scanf("%d%d",&n,&m);
int i,j,x,y,w;
scanf("%s",str+);
for(i=;i<=n;i++) a[i]=(str[i]=='(')?:;
for(i=;i<=m;i++)
{
scanf("%s",str);
if(str[]=='R'){
x=gint(), y=gint(), scanf("%s",str);
w=(str[]=='(')?:;
for(j=x;j<=y;j++) a[j]=w;
}else if(str[]=='S'){
x=gint(), y=gint();
for(j=x;j<=y;j++) tmp[j-x+]=a[j];
for(j=x;j<=y;j++) a[j]=tmp[y-j+];//y-j+1
}else if(str[]=='I'){
x=gint(), y=gint();
for(j=x;j<=y;j++) a[j]^=;
}else if(str[]=='Q'){
x=gint(), y=gint();
int sum=,ans=,ret=;
for(j=x;j<=y;j++)
{
if(!a[j]) sum++;
else if(sum>) sum--;
else ans++;
}
ret+=ans/+((ans&)?:); sum=ans=;
for(j=y;j>=x;j--)
{
if(a[j]) sum++;
else if(sum>) sum--;
else ans++;
}
ret+=ans/+((ans&)?:);
printf("%d\n",ret);
}
//debug();
}
return ;
}
数据生成器:
#include <bits/stdc++.h>
using namespace std; int main()
{
srand(time(NULL));
int n=,m=,i,x,l,r,t;
printf("%d %d\n",n,m);
for(i=;i<=n;i++) x=rand()%,printf("%c",(x&)?')':'(');
puts("");
for(i=;i<=m;i++)
{
x=rand()%; l=rand()%n+; r=rand()%n+;
if(l>r) swap(l,r);
if(x==){
x=rand()%;
printf("Replace %d %d %c\n",l,r,(x&)?')':'(');
}else if(x==){
printf("Swap %d %d\n",l,r);
}else if(x==){
printf("Invert %d %d\n",l,r);
}else{
l=(rand()%(n/))*+,r=(rand()%(n/)+)*;
if(l>r) swap(l,r);
printf("Query %d %d\n",l,r);
}
}
return ;
}
BZOJ 2329/2209 [HNOI2011]括号修复 (splay)的更多相关文章
- BZOJ 2329: [HNOI2011]括号修复( splay )
把括号序列后一定是))))((((这种形式的..所以维护一个最大前缀和l, 最大后缀和r就可以了..答案就是(l+1)/2+(r+1)/2...用splay维护,O(NlogN). 其实还是挺好写的, ...
- BZOJ 2329: [HNOI2011]括号修复 [splay 括号]
题目描述 一个合法的括号序列是这样定义的: 空串是合法的. 如果字符串 S 是合法的,则(S)也是合法的. 如果字符串 A 和 B 是合法的,则 AB 也是合法的. 现在给你一个长度为 N 的由‘(' ...
- BZOJ2329 HNOI2011 括号修复 splay+贪心
找平衡树练习题的时候发现了这道神题,可以说这道题是近几年单考splay的巅峰之作了. 题目大意:给出括号序列,实现区间翻转,区间反转和区间更改.查询区间最少要用几次才能改成合法序列. 分析: 首先我们 ...
- 【bzoj2329】[HNOI2011]括号修复 Splay
题目描述 题解 Splay 由于有区间反转操作,因此考虑Splay. 考虑答案:缩完括号序列后剩下的一定是 $a$ 个')'+ $b$ 个'(',容易发现答案等于 $\lceil\frac a2\rc ...
- BZOJ2329: [HNOI2011]括号修复(Splay)
解题思路: Replace.Swap.Invert都可以使用Splay完美解决(只需要解决一下标记冲突就好了). 最后只需要统计左右括号冲突就好了. 相当于动态统计最大前缀合和最小后缀和. 因为支持翻 ...
- ●BZOJ 2329 [HNOI2011]括号修复.cpp
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2329 题解: Splay 类似 BZOJ 2329 [HNOI2011]括号修复 只是多了一 ...
- 【BZOJ2329/2209】[HNOI2011]括号修复/[Jsoi2011]括号序列 Splay
[BZOJ2329/2209][HNOI2011]括号修复/[Jsoi2011]括号序列 题解:我们的Splay每个节点维护如下东西:左边有多少多余的右括号,右边有多少多余的左括号,同时为了反转操作, ...
- 【BZOJ-2329&2209】括号修复&括号序列 Splay
2329: [HNOI2011]括号修复 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 1007 Solved: 476[Submit][Statu ...
- bzoj千题计划222:bzoj2329: [HNOI2011]括号修复(fhq treap)
http://www.lydsy.com/JudgeOnline/problem.php?id=2329 需要改变的括号序列一定长这样 :)))((( 最少改变次数= 多余的‘)’/2 [上取整] + ...
随机推荐
- python之接口继承
接口继承 接口继承就是(基类)父类定义好2个函数属性(接口),所有的子类必须有这2个函数属性,缺一不可,不是说省代码的,是用来做强制性约束的 基类里面的方法不用具体的实现,只是一个规范而已 1.1实现 ...
- Bonjour/Zeroconf with Arduino
转自:http://gkaindl.com/software/arduino-ethernet/bonjour Bonjour/Zeroconf with Arduino DownloadVersio ...
- [luogu4037 JSOI2008] 魔兽地图 (树形dp)
传送门 Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the ...
- [luogu3237 HNOI2014] 米特运输 (树形dp)
传送门 Description 米特是D星球上一种非常神秘的物质,蕴含着巨大的能量.在以米特为主要能源的D星上,这种米特能源的运输和储存一直是一个大问题. D星上有N个城市,我们将其顺序编号为1到N, ...
- Java基础学习总结(63)——Java集合总结
数据结构是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作.Java提供了几个能有效地组织和操作数据的数据结构,这些数据结构通常称为Java集合框架.在平常的学习开发中,灵 ...
- 使用动态代理实现dao接口
使用动态代理实现dao接口的实现类 MyBatis允许只声明一个dao接口,而无需写dao实现类的方式实现数据库操作.前提是必须保证Mapper文件中的<mapper>标签的namespa ...
- BA-siemens-点位类型表
X(超级点) 输入 0-10v 4-20ma(不可用) Ni 1000 Pt 1000 10k & 100k 热敏电阻 数字输入 脉冲计数输入 输出 0-10v 4-20ma(不可用) 数字 ...
- 初探swift语言的学习笔记十(block)
作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/35783341 转载请注明出处 假设觉得文章对你有所帮助,请通过留言 ...
- sqlite学习笔记7:C语言中使用sqlite之打开数据库
数据库的基本内容前面都已经说得差点儿相同了.接下看看如何在C语言中使用sqlite. 一 接口 sqlite3_open(const char *filename, sqlite3 **ppDb) 打 ...
- Deming管理系列(1)——开车仅仅看后视镜
问题: 当业务经理被要求为未来的业务做计划时,他会提出一个自觉得不错的数字,而董事会往往希望能获得更大的收益,多次与其谈判.而业务经理在这方面不是新手,他有非常多可用的报告. 为什么不能让业务规划流程 ...