前置芝士:线段树 (应该会的吧)
本题可以算线段树的基本操作了,进入正题吧:
我们线段树中存储三个变量:
-
(sum[x]) :完整的木棒的数量
-
(ls[x]) :最右边的括号是否是 (
-
(rs[x]) :最左边的括号是否是 )
做题过程分为建树,单点修改和查询 (很经典了吧)
本题在建树和单点修改时只有一点与其他节点不同,就是合并节点信息,在这里略作解释:
首先是最简单直接赋值:
(rs_x=rs_{sonL},ls_x=ls_{sonR})
(sum_x=sum_{sonL}+sum_{sonR}+[ls_{sonL}==1&&rs_{sonR}==1])
另外注意一点,当(sonL)的区集中全是(X)时,(rs_x)是要等于(rs_{sonR})的,而且易证得,如果(sum_{sonL}==0&&rs_{sonL}==0&&ls_{sonL}==0),则可以说明左儿子全是(X),因此合并部分代码如下:
inline void update(int x)
{
rs[x]=rs[x<<1],ls[x]=ls[x<<1|1];
if(sum[x<<1]==0&&ls[x<<1]==0&&rs[x<<1]==0) rs[x]=rs[x<<1|1];
if(sum[x<<1|1]==0&&ls[x<<1|1]==0&&rs[x<<1|1]==0) ls[x]=ls[x<<1];
sum[x]=sum[x<<1]+sum[x<<1|1]+(ls[x<<1]+rs[x<<1|1]>>1);
}
再就是查询了,这里需要用到一个小技巧,线段树的遍历顺序是从左往右的,所以我们每遇到一个合法区间,和前一个遇到的合法区间合并计算答案就好了,同样需要注意全为(X)的情况。
(OVER)~~
完整代码如下:
#include<bits/stdc++.h>
#define re register
using namespace std;
inline int read()
{
re int x=0,f=1;
re char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') f*=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
return x*f;
}
const int N=200005;
int n,m,sum[N<<2],ans;
bool ls[N<<2],rs[N<<2],last;
char ch[N],s[1];
inline void update(int x)
{
rs[x]=rs[x<<1],ls[x]=ls[x<<1|1];
if(sum[x<<1]==0&&ls[x<<1]==0&&rs[x<<1]==0) rs[x]=rs[x<<1|1];
if(sum[x<<1|1]==0&&ls[x<<1|1]==0&&rs[x<<1|1]==0) ls[x]=ls[x<<1];
sum[x]=sum[x<<1]+sum[x<<1|1]+(ls[x<<1]+rs[x<<1|1]>>1);
}
void build(int l,int r,int x)
{
if(l==r) {ls[x]=(ch[l]=='('),rs[x]=(ch[l]==')');return ;}
re int mid=l+r>>1;
build(l,mid,x<<1),build(mid+1,r,x<<1|1);
update(x);
}
void change(int l,int r,int x,int p,char a)
{
if(l==r) {ls[x]=(a=='('),rs[x]=(a==')');return ;}
re int mid=l+r>>1;
if(p<=mid) change(l,mid,x<<1,p,a);
else change(mid+1,r,x<<1|1,p,a);
update(x);
}
void ask(int l,int r,int x,int L,int R)
{
if(L<=l&&r<=R)
{
if(sum[x]==0&&ls[x]==0&&rs[x]==0) return ;
ans+=sum[x]+(last+rs[x]>>1);
last=ls[x];//last为上一个合法区间最右边一个括号是否为 (
return ;
}
re int mid=l+r>>1;
if(L<=mid) ask(l,mid,x<<1,L,R);
if(R>mid) ask(mid+1,r,x<<1|1,L,R);
}
inline void Fre()
{
freopen("P3797.in","r",stdin);
freopen("P3797.out","w",stdout);
}
int main()
{
Fre();
n=read(),m=read();
for(re int i=2;i<n;i++) ch[i]='X';ch[1]='(',ch[n]=')';
build(1,n,1);
for(re int i=1,type,x,y;i<=m;i++)
{
type=read(),x=read();
if(type==1)
{
scanf("%s",s);
change(1,n,1,x,s[0]);
}
else
{
y=read(),ask(1,n,1,x,y);
printf("%d
",ans);
ans=last=0;
}
}
return 0;
}