[题解]luogu_P3797_(线段树
由于木棒不可嵌套,所以能组成新木棒的只有可能是最中间的两个括号,即左区间最靠右的和右区间最靠左的括号,所以线段树可以维护这些信息,合并时多多判断(不要弄混,还多记了一个tg表示区间是否全部由x构成帮助更新
#include<bits/stdc++.h> #define ls (x<<1) #define rs (x<<1|1) #define mid (l+r>>1) using namespace std; const int maxn=200009; int n,m; struct node{ int sum,lc,rc,tg;//最右的左括号,最左的右括号 是否全是X }t[maxn<<2]; inline void upd(int x){ t[x].sum=t[ls].sum+t[rs].sum; if(t[ls].lc && t[rs].rc)t[x].sum++; if(t[rs].lc)t[x].lc=t[rs].lc; else if(t[rs].tg && t[ls].lc)t[x].lc=t[ls].lc; else t[x].lc=0; if(t[ls].rc)t[x].rc=t[ls].rc; else if(t[ls].tg && t[rs].rc)t[x].rc=t[rs].rc; else t[x].rc=0; if(t[ls].tg&&t[rs].tg)t[x].tg=1; else t[x].tg=0; } inline void build(int x,int l,int r){ if(l==r){ if(l==1)t[x].lc=l; else if(l==n)t[x].rc=l; else t[x].tg=1; return ; } build(ls,l,mid);build(rs,mid+1,r); upd(x); } inline void change(int x,int l,int r,int pos,int val){ if(l==r){ if(val==1)t[x].lc=l,t[x].rc=0,t[x].tg=0; else if(val==2)t[x].rc=l,t[x].lc=0,t[x].tg=0; else t[x].tg=1,t[x].lc=t[x].rc=0; return; } if(pos<=mid)change(ls,l,mid,pos,val); else change(rs,mid+1,r,pos,val); upd(x); } inline int query(int x,int l,int r,int L,int R){ if(L<=l && r<=R){ return t[x].sum; } int ans=0; if(L<=mid)ans+=query(ls,l,mid,L,R); if(R>mid)ans+=query(rs,mid+1,r,L,R); if(t[ls].lc>=L && t[rs].rc<=R && t[rs].rc && t[ls].lc)ans++; return ans; } int main(){ // freopen("testdata (4).in","r",stdin); scanf("%d%d",&n,&m); build(1,1,n);char s[5]; for(int i=1,op,l,r;i<=m;i++){ scanf("%d",&op); if(op==1){ scanf("%d",&l);scanf("%s",s); if(s[0]=='(')change(1,1,n,l,1); else if(s[0]==')')change(1,1,n,l,2); else change(1,1,n,l,0); } else{ scanf("%d%d",&l,&r); printf("%d\n",query(1,1,n,l,r)); } } }