分析:该題可以用线段树做,也可以用树状数组做;感觉树状数组容易一些,这里就用树状数组了。这里保存字符数组的下标从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;
}原文地址:http://blog.csdn.net/a809146548/article/details/45675161