题意:
给一个字符串,两种操作 0 a b 询问a,b之间有多少个wbw, 1 a c 就是把第a个改成c.
思路:
这个题目我们可以用线段树的点更新来做,一开始写了个好长好长的线段树,pushup写了很长,每个节点7个变量,结果 "呵呵"。其实根本不用那么麻烦,我当时想的麻烦了,每个节点只有一个sum就行了,每个节点代表的是以当前这段的每个点为终点的wbw的个数,比如节点4,6那么当前的这个节点存的就是以4,5,6,为终点的wbw的个数(4,6最多三个),每次更新的时候改变当前的这个字母可能会影响三个权值改变,所以更新三次,具体看代码。
#include<stdio.h>
#include<string.h>
#define lson l ,mid ,t << 1
#define rson mid + 1 ,r ,t << 1 | 1
int sum[300000];
char num[55000];
void Pushup(int t)
{
sum[t] = sum[t<<1] + sum[t<<1|1];
}
void BuidTree(int l ,int r ,int t)
{
sum[t] = 0;
if(l == r)
{
if(l >= 3 && num[l] == 'w' && num[l-1] == 'b' && num[l-2] == 'w')
sum[t] = 1;
return ;
}
int mid = (l + r) >> 1;
BuidTree(lson);
BuidTree(rson);
Pushup(t);
}
void Update(int l ,int r ,int t ,int a)
{
if(l == r)
{
if(num[l] == 'w' && num[l-1] == 'b' && num[l-2] == 'w')
sum[t] = 1;
else sum[t] = 0;
return;
}
int mid = (l + r) >> 1;
if(a <= mid) Update(lson ,a);
else Update(rson ,a);
Pushup(t);
}
int Query(int l ,int r ,int t ,int a ,int b)
{
if(a <= l && b >= r)
return sum[t];
int mid = (l + r) >> 1;
int Ans = 0;
if(a <= mid) Ans = Query(lson ,a ,b);
if(b > mid) Ans += Query(rson ,a ,b);
return Ans;
}
int main ()
{
int t ,n ,m ,a ,b ,c ,cas = 1;
scanf("%d" ,&t);
while(t--)
{
scanf("%d %d" ,&n ,&m);
scanf("%s" ,num + 1);
BuidTree(1 ,n ,1);
printf("Case %d:\n" ,cas ++);
while(m--)
{
scanf("%d" ,&a);
if(!a)
{
scanf("%d %d" ,&b ,&c);
b ++ ,c ++;
if(c - b < 2) printf("0\n");
else printf("%d\n" ,Query(1 ,n ,1 ,b + 2 ,c));
}
else
{
char str[5];
scanf("%d %s" ,&b ,str);
num[++b] = str[0];
if(b >= 3) Update(1 ,n ,1 ,b);
if(b + 1 >= 3 && b + 1 <= n) Update(1 ,n ,1 ,b + 1);
if(b + 2 >= 3 && b + 2 <= n) Update(1 ,n ,1 ,b + 2);
}
}
}
return 0;
}