前置芝士:线段树 (应该会的吧)
本题可以算线段树的基本操作了,进入正题吧:
我们线段树中存储三个变量:
-
\(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\n",ans);
ans=last=0;
}
}
return 0;
}