题目链接:Query on a string
题目大意:有一个原串和模式串,有下面两种操作Q X Y,查询原串里面X到Y这跟区间模式串出现了多少次,C X Y,把X位置的这跟字符修改为Y
题目思路:我们可以预处理一下原串,如果这个点往后延伸得到了模式串,那么我们将这个点置为1,否则为1,然后查询的时候区间求和就好了,修改暴力去修改就好了,因为模式串只有10的长度,所以修改的长度很小,修改的时候被影响的地方需要改动,因为是单点修改+区间求和,所以树状数组就ok了(查询的时候不是X到Y,因为要在这个区间的所有字符,所以查询到Y-L2+1就好了)
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
int N,c[maxn];
int T,q;
char str[maxn],mo[maxn];
bool flag,vis[maxn];
int lowbit(int i){
return i&(-i);
}
void add(int i,int value){
while(i <= N){
c[i] += value;
i += lowbit(i);
}
}
int getsum(int i){
int sum = 0;
while(i > 0){
sum += c[i];
i -= lowbit(i);
}
return sum;
}
int main(){
scanf("%d",&T);
getchar();
while(T--){
scanf("%d",&q);
memset(c,0,sizeof(c));
memset(vis,false,sizeof(vis));
getchar();
scanf("%s%s",str+1,mo+1);
int l1 = strlen(str+1),l2 = strlen(mo+1);
N = l1;
for(int i = 1;i <= l1-l2+1;i++){
flag = true;
for(int j = 1;j <= l2;j++){
if(str[i+j-1] != mo[j]) flag = false;
}
if(flag){
add(i,1);
vis[i] = true;
}
}
while(q--){
char op;
scanf("\n%c",&op);
if(op == 'Q'){
int st,ed;
scanf("%d%d",&st,&ed);
if(ed-l2+1 >= st) printf("%d\n",getsum(ed-l2+1)-getsum(st-1));
else puts("0");
}
else{
int num;
char ch;
scanf("%d %c",&num,&ch);
str[num] = ch;
for(int i = max(1,num-l2+1);i <= min(num,l1-l2+1);i++){
flag = true;
for(int j = 1;j <= l2;j++){
if(str[i+j-1] != mo[j]) flag = false;
}
if(flag != vis[i]){
if(vis[i]) add(i,-1);
else add(i,1);
vis[i] = !vis[i];
}
}
}
}
puts("");
}
return 0;
}