括号修复
Description
作为当年负责讲解splay的本蒟蒻突然发现自己不记得splay怎么打了……
在经历了一番激烈的思想斗争后决定回来复习一下。
(因为咱突然发现6个多月过去了咱还从来没有用过平衡树系列的东西)
然后就被此题玩了个半死……
(╯‵□′)╯︵┻━┻
思路:
那些操作一看就是在钦定splay了……
然后考虑如何兹瓷询问。
假设现在有一个奇怪的括号序列:
))()()(((()))(()
咱来配个对:
))((
那么这就是咱要的答案:2/2+2/2=2。
也就是(左括号数+1)/2+(右括号数+1)/2(加一即向上取整)
如何维护消去后的左括号数和右括号数?
令’(‘为1,’)’为-1
那么可以发现,左括号数值就是前缀和的最小值,右括号数就是后缀和的最大值。
也就是左起最小和右起最大。
考虑到几种操作,或许咱们需要维护左起最大最小、右起最大最小四个tag?
理论上是的,但其实只需要左起最大最小,一共两个tag就够了……
考虑swap,交换左起最大和右起最小,右起最大和左起最小。
只维护两个的话,左起最大会变成区间和减去原左起最小,左起最小同理。
考虑invert,交换左起最大和左起最小,右起最大和右起最小。
只维护两个的话,同时乘以-1并交换位置就好。
考虑Replace,咱认为这不需要考虑。
考虑Query,可以发现右起最大加上左起最小的值等于区间和。
然后就没有然后了……
等等你说许多题解提到了一个tag的更新顺序?
事实上只需要在下传tag时优先Replace,并在更新时顺手清空子树的Invert标记即可~
因为在拥有了Replace标记后,子树的Invert标记被无效化了,此时咱们再下传当前节点的有效的Invert标记,就可以不打乱顺序了~
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=1000009;
int n,q,root;
char s[N];
int ch[N][2],fa[N],val[N],siz[N],sum[N],tot;
int up[N],down[N],rev[N],inv[N],rep[N];
inline int maxx(int a,int b){if(a>b)return a;return b;}
inline int minn(int a,int b){if(a<b)return a;return b;}
inline void update(int x)
{
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+val[x];
up[x]=maxx(up[ch[x][0]],up[ch[x][1]]+sum[ch[x][0]]+val[x]);
down[x]=minn(down[ch[x][0]],down[ch[x][1]]+sum[ch[x][0]]+val[x]);
}
inline void invert(int x)
{
inv[x]^=1;
val[x]=-val[x];
sum[x]=-sum[x];
down[x]=-down[x];
up[x]=-up[x];
swap(up[x],down[x]);
}
inline void replace(int x,int ty)
{
inv[x]=0;
rep[x]=ty;
if(ty==1)
{
val[x]=1;sum[x]=siz[x];
up[x]=siz[x];down[x]=0;
}
else
{
val[x]=-1;sum[x]=-siz[x];
up[x]=0;down[x]=-siz[x];
}
}
inline void reverse(int x)
{
rev[x]^=1;
up[x]=sum[x]-up[x];
down[x]=sum[x]-down[x];
swap(up[x],down[x]);
}
inline void push(int x)
{
if(rev[x])
{
swap(ch[x][0],ch[x][1]);
reverse(ch[x][0]);
reverse(ch[x][1]);
rev[x]=0;
}
if(rep[x])
{
replace(ch[x][0],rep[x]);
replace(ch[x][1],rep[x]);
rep[x]=0;
}
if(inv[x])
{
invert(ch[x][0]);
invert(ch[x][1]);
inv[x]=0;
}
}
inline void prepush(int x)
{
if(fa[x])
prepush(fa[x]);
push(x);
}
inline int find(int x,int k)
{
push(x);
if(k==siz[ch[x][0]]+1)
return x;
else if(k<=siz[ch[x][0]])
return find(ch[x][0],k);
else
return find(ch[x][1],k-siz[ch[x][0]]-1);
}
inline void rotate(int x)
{
int y=fa[x],z=fa[y];
int l=(ch[y][1]==x);
if(z)ch[z][ch[z][1]==y]=x;
fa[x]=z;fa[y]=x;fa[ch[x][l^1]]=y;
ch[y][l]=ch[x][l^1];ch[x][l^1]=y;
update(y);update(x);
}
inline int build(int l,int r)
{
if(l>r)return 0;
int mid=l+r>>1,now=++tot;
val[now]=(s[mid]=='('?1:-1);
ch[now][0]=build(l,mid-1);
ch[now][1]=build(mid+1,r);
fa[ch[now][0]]=fa[ch[now][1]]=now;
update(now);
return now;
}
inline void splay(int x,int target=0)
{
prepush(x);
while(fa[x]!=target)
{
int y=fa[x],z=fa[y];
if(z!=target)
{
if((ch[y][0]==x)^(ch[z][0]==y))rotate(x);
else rotate(y);
}
rotate(x);
}
if(!target)
root=x;
update(x);
}
int main()
{
scanf("%d%d",&n,&q);
scanf("%s",s+1);
root=build(0,n+1);
for(int i=1,l,r;i<=q;i++)
{
scanf("%s%d%d",s+1,&l,&r);
l=find(root,l);
r=find(root,r+2);
splay(l);
splay(r,root);
if(s[1]=='R')
{
scanf("%s",s+1);
replace(ch[r][0],s[1]=='('?1:-1);
}
else if(s[1]=='S')
reverse(ch[r][0]);
else if(s[1]=='I')
invert(ch[r][0]);
else
printf("%d\n",(-down[ch[r][0]]+1)/2+(sum[ch[r][0]]+(-down[ch[r][0]]+1)/2*2)/2);
update(l);
update(r);
}
return 0;
}