题意:
给了一列字符串(最长50000)...字符串仅由w,b组成..现在有两个操作..
0 l r : 询问区间[l,r]有多少个wbw..输出..
1 x c: 将第x位置变成c(c=w or b)
题解:
大致的思想是先用树状数组统计出前缀和..询问的时候就可以直接得出一段的wbw个数了..而修改..则将与修改位相关的前缀和都置为0..然后重新计算...
做的时候要注意一些处理..我用树状数组询问一点x是问从1~x有多少个wbw...一般的问题都是sum[r]-sum[l-1]得出区间[l,r]的所需个数...而对于一个区间的询问如 wbw ...询问[2,3](我的本题字符串下标设置为从1开始)...此时sum[1]=0,sum[3]=1..答案为1..显然是错的...因为2的位置让3号位得不到1..又如wbwbw..询问[2,5]..sum[1]=0,sum[5]=2...答案为2..显然也是错的..询问[4,5]..sum[3]=1,sum[5]=2..答案为1..同样也不对....问题就出在计算[l,r]里wbw的个数时.右界可以用sum[r]..而左界要到l的右侧来计算.因为如果计算r的个数时计算了 *l****r 这种..跨过l的不应该算..
Program:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define MAXN 50505
using namespace std;
char s[MAXN],c;
int sum[MAXN],A[MAXN],n;
void update(int k,int x)
{
while (k<=n)
{
sum[k]+=x;
k+=k&(-k);
}
}
int query(int k)
{
int ans=0;
while (k)
{
ans+=sum[k];
k-=k&(-k);
}
return ans;
}
int main()
{
int T,cas,i,m,t,l,r,x;
scanf("%d",&T);
for(int cas=1;cas<=T;++cas)
{
scanf("%d%d",&n,&m);
printf("Case %d:\n",cas);
if (!n) continue;
s[0]='!';
scanf("%s",s+1);
memset(sum,0,sizeof(sum));
memset(A,0,sizeof(A));
for (i=3;i<=n;i++)
if (s[i-2]=='w' && s[i-1]=='b' && s[i]=='w') A[i]=1,update(i,1);
while (m--)
{
scanf("%d",&t);
if (!t)
{
scanf("%d%d",&l,&r),l+=3,r++;
l=min(l,r+1);
printf("%d\n",max(0,query(r)-query(l-1)));
}
else
{
scanf("%d %c",&x,&c),x++;
if (s[x]==c) continue;
s[x]=c;
l=max(x,3),r=min(n,x+2);
for (i=l;i<=r;i++)
{
update(i,-A[i]),A[i]=0;
if (s[i-2]=='w' && s[i-1]=='b' && s[i]=='w')
A[i]=1,update(i,1);
}
}
}
}
return 0;
}