题目:http://acm.hdu.edu.cn/showproblem.php?pid=4046
题意:给出一个字符串,统计这个字符串任意区间中“wbw”出现的次数。
规定两种操作,一是查询任意区间“wbw”出现次数;二是修改某一位置的字符。
分析:比较明显的线段树,单点更新,区间查询。
线段树记录的信息是区间中出现“wbw”字符的个数,线段树的叶子节点[i,i]记录字符串str中
str[i-2][i-1][i]是否是“wbw“。
对于字符的修改,这里就有要注意了。修改的位置pos, 可能对线段树中sum[pos-1] sum[pos] 或sum[pos+1]
造成影响。这里要分情况。
代码
#include<cstdio>#include<cstring>#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;const int maxn=50010;int n,m,sum[maxn<<2];
char str[maxn];
int num[maxn];
void pushup(int rt){sum[rt]=sum[rt<<1]+sum[rt<<1|1];}void build(int l,int r,int rt){if(l==r)
{sum[rt]=num[l];return;
}int m=(l+r)>>1;
build(lson);build(rson);pushup(rt);}int query(int L,int R,int l,int r,int rt){if(L<=l&&r<=R)
{return sum[rt];
}int m=(l+r)>>1;
int ans=0;
if(L<=m) ans+=query(L,R,lson);
if(R>m) ans+=query(L,R,rson);
return ans;
}void update(int p,int val,int l,int r,int rt){if(l==r)
{sum[rt]=val;return;
}int m=(l+r)>>1;
if(p<=m) update(p,val,lson);
else update(p,val,rson);
pushup(rt);}int main()
{int t,T;
scanf("%d",&T);
for(int t=1;t<=T;t++){printf("Case %d: ",t);
scanf("%d%d%s",&n,&m,str+1);
memset(num,0,sizeof(num));
for(int i=3;i<=n;i++)if(str[i-2]=='w'&&str[i-1]=='b'&&str[i]=='w') num[i]=1;
build(1,n,1);int k,a,b;
char ch[5];
while (m--)
{scanf("%d",&k);
if(k==0)
{scanf("%d%d",&a,&b);
a++;b++; //字符串从1开始,所以下标都加1
if(b-a<2) printf("0 ");else printf("%d ",query(a+2,b,1,n,1));}else
{scanf("%d%s",&a,ch);
a++;if(ch[0]==str[a]) continue;//修改的和以前一样,这不用任何操作if(a>=3)
{if(str[a-2]=='w'&&str[a-1]=='b'&&str[a]=='w')
update(a,0,1,n,1);if(str[a-2]=='w'&&str[a-1]=='b'&&str[a]=='b')
update(a,1,1,n,1);}if(a>=2&&a+1<=n)
{if(str[a-1]=='w'&&str[a]=='b'&&str[a+1]=='w')
update(a+1,0,1,n,1);if(str[a-1]=='w'&&str[a]=='w'&&str[a+1]=='w')
update(a+1,1,1,n,1);}if(a+2<=n)
{if(str[a]=='w'&&str[a+1]=='b'&&str[a+2]=='w')
update(a+2,0,1,n,1);if(str[a]=='b'&&str[a+1]=='b'&&str[a+2]=='w')
update(a+2,1,1,n,1);}str[a]=ch[0];}}}return 0;
}