分析:该題可以用线段树做,也可以用树状数组做;感觉树状数组容易一些,这里就用树状数组了。这里保存字符数组的下标从1开始,树状数组初始化从3开始,因为只有大于等于3使才可能有符合要求的字串出现,最终计算L到R区间的个数时要用getsum(R)-getsum(L+1),因为可能有符合要求的str[L-1],str[L],str[l+1]也被算进去了,实际上他并不在区间L到R内。更新时要注意三种情况,POS,POS+1,POS+2处的都会受影响。
#include<iostream> using namespace std; int c[50010]; int n; char str[50010]; int lowbit(int x) { return x&(-x); } void update(int x,int v) { int i; for(i=x;i<=n;i+=lowbit(i)) c[i]+=v; } bool valid(char x,char y,char z) { return x=='w' && y=='b' && z=='w'; } void init() { int i; memset(c,0,sizeof(c)); for(i=3;i<=n;i++) if(valid(str[i-2],str[i-1],str[i])) update(i,1); } int getsum(int x) { int sum,i; for(i=x,sum=0;i>0;i-=lowbit(i)) sum+=c[i]; return sum; } int main() { int T,m,L,R,op,t; int pos,k; char r[4],ch; ios::sync_with_stdio(false); cin>>T; t=0; while(T--) { cin>>n>>m; cin>>(str+1); //字符串从1开始编号 init(); cout<<"Case "<<++t<<":"<<endl; while(m--) { cin>>op; if(op==0) { cin>>L>>R; L++; R++; if(R-L<2) cout<<0<<endl; else //注意str[L-1],str[L],str[L+1]可能也符合要求,但不在区间范围内,所以减去L+1以便出去这种情况 cout<<getsum(R)-getsum(L+1)<<endl; } else { cin>>pos>>ch; pos++; if(str[pos]==ch) continue; r[0]=str[pos-2]; r[1]=str[pos-1]; r[2]=ch; for(k=0;k<=2;k++) //三种情况 { if(pos>=3 && pos<=n) { if(valid(str[pos-2],str[pos-1],str[pos]) && !valid(r[0],r[1],r[2])) update(pos,-1); if(!valid(str[pos-2],str[pos-1],str[pos]) && valid(r[0],r[1],r[2])) update(pos,1); } pos++; if(k==0) { r[0]=str[pos-2]; r[1]=ch; r[2]=str[pos]; } else { r[0]=ch; r[1]=str[pos-1]; r[2]=str[pos]; } } str[pos-3]=ch; } } } return 0; }
时间: 2024-10-13 16:00:16