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 [上取整] + ...
随机推荐
- php设置cookie和删除cookie
设置cookie Example : - set - <?php setcookie( "name", "value", "future_tim ...
- 会话cookie和持久化cookie实现session
当你第一次访问一个网站的时候,网站服务器会在响应头内加上Set- Cookie:PHPSESSID=nj1tvkclp3jh83olcn3191sjq3(php服务器),或Set-Cookie JSE ...
- Linux Shell脚本编程-数组和字符串处理
数组 1.数组的定义及声明 变量:存储单个元素的内存空间 数组:存储多个元素的连续的内存空间,相当于多个变量的集合 数组名:整个数组只有一个名字 索引:编号从0开始,属于数值索引:bash的数组支持 ...
- tomcat 内存溢出问题(OutOfMemoryError: PermGen space)
导入公司项目的时候出现的问题,在此记录处理方法. tomcat在启动的时候报错:OutOfMemoryError: PermGen space PermGen space的全称是Permanent G ...
- [SQL]存储过程建表
create PROC [dbo].CreateUserTable ( @name NVARCHAR(60) ) AS DECLARE @a NVARCHAR(max) SET @a='create ...
- HDU 4345
细心点想,就明白了,题目是求和为N的各数的最小公倍数的种数.其实就是求N以内的各素数的不同的组合(包含他们的次方),当然,是不能超过N的.用Dp能解决.和背包差不多. #include <ios ...
- HDU 4767
昨晚苦恼了一晚,因为即将大三了,必须要准备实习什么的事了.一般都会去公司实习吧,但是看看自己的简历,实在拿不出手,因为大一大二都在搞ACM(虽然真正搞的只有大二一年),但却没有什么成绩,又不愿意做项目 ...
- OC-JS交互(WebViewJavascriptBridge使用说明)
首先确保一份已经配好功能的html文件. 1.初始化一个webview(viewdidload) UIWebView* webView = [[UIWebView alloc] initWithFra ...
- Nagios监控nginx服务具体过程
1在nginx 服务器上安装nrpe客户端: Nginx的服务须要监控起来.不然万一down了而不及时修复,会影响web应用.例如以下web应用上面启动的nginx后台进程[root@lb-net-2 ...
- C++中 pair 的使用方法
#include<iostream> #include<string> #include<map> using namespace std; // pair简单讲就 ...