题意:给一个字符串中,0:L,R为L到R之间有多少个连续的wbw,可以重叠。1:p,ch为在字符串中的p位置改为ch。n为字符串的长度,m为操作的次数。
思路:这道题没能该出来很自责,因为很简单。更改一个占位置最多只影响到三个位置。每个位置代表从这位置开始往后连续的三个字符是否为"wbw"。用梳妆数组统计就可以了。注意跟换之前和之后的变化关系。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N=78000;
int C[N*2];
char str[N];
int n,m;
int lowbit(int a)
{
return a&(-a);
}
int getsum(int p)
{
int ans=0;
for(int i=p;i>0;i-=lowbit(i))
ans+=C[i];
return ans;
}
void Modify(int p,int c)
{
for(int i=p;i<=n+2;i+=lowbit(i))
C[i]+=c;
}
void solve(int p,char ch)
{
int a=0;
for(int i=p-2;i<=p;i++)//更换之前如果相等先减一,如果替换之后还一样就加一,就相当于不加比之前的节约代码量
{
a++;
if(a>6)break;
if(i<0||(i+2>=n)||(i+1>=n))
continue;
if(str[i]=='w'&&str[i+1]=='b'&&str[i+2]=='w')
Modify(i+1,-1);
}
str[p]=ch;
for(int i=p-2;i<=p;i++)//更换之后
{
if(i<0||(i+2>=n)||(i+1>=n))
continue;
if(str[i]=='w'&&str[i+1]=='b'&&str[i+2]=='w')
Modify(i+1,1);
}
}
int main()
{
int cas;
scanf("%d",&cas);
int T=0;
while(cas--)
{
scanf("%d%d",&n,&m);
scanf("%s",str);
int len=strlen(str);
memset(C,0,sizeof(C));
if(len>=3)
for(int i=0;i<len-2;i++)
{
if(str[i]=='w'&&str[i+1]=='b'&&str[i+2]=='w')
Modify(i+1,1);
}
int ch;
int a,b;
char vv[20];
printf("Case %d:\n",++T);
while(m--)
{
scanf("%d",&ch);
if(ch==0)
{
scanf("%d%d",&a,&b);
if(b-a+1<3)
{
printf("0\n");
continue;
}
int ans=getsum(b-1)-getsum(a);
printf("%d\n",ans);
}
else if(ch==1)
{
scanf("%d %s",&b,vv);
getchar();
solve(b,vv[0]);
}
}
}
return 0;
}