题意
给定字符串
S
和
两种操作:
1. 修改
S
串某个位置的字符
2. 询问
题解
如果没有修改,我们可以对
T
建
当修改某个字符时,01数组中受到影响的显然最多是10个位置,即每次修改操作暴力kmp并修改对应位置的01数组即可。这样一次修改就是
O(logn)
的,常数为10左右。于是整体复杂度
O(qlogn)
。
代码
#include <bits/stdc++.h>
#define kN 100010LL
#define kL 100010LL
#define lb (p&(-p))
int q,n,m,fail[20],C[kL];
bool ok[kL];
char s[kL],t[20];
inline void ins(int p,int w){
for(;p<=n;p+=lb)C[p]+=w;
}
inline int sum(int p) {
int ret=0;for(;p>0;p-=lb)ret+=C[p];return ret;
}
inline void getfail() {
int i, p = 0;
fail[1] = 0;
for(i=2;i<=m;i++) {
while(p&&t[p+1]!=t[i])p=fail[p];
p+=(t[p+1]==t[i]), fail[i] = p;
}
}
inline void Query(int l,int r) {
l += m-1;
if (l<=r) printf("%d\n",sum(r)-sum(l-1));
else puts("0");
}
inline void Change(int p,char c) {
if (c == s[p]) return;
s[p] = c;
int l = p-m+1, r = p+m-1, i;
if (l<1) l = 1;
if (r > n) r = n;
int pos = p;
p = 0;
for(i = l;i <= r;i ++ ) {
while(p && t[p+1]!=s[i]) p = fail[p];
p += (t[p+1]==s[i]);
if (i >= pos) {
if (p == m) {
if (!ok[i]) ok[i]=true,ins(i,1);
} else {
if (ok[i]) ok[i] = false, ins(i,-1);
}
}
}
}
inline void work() {
int p, i, j, k;
char mode, c;
scanf("%d%s%s",&q,s+1,t+1);
n=strlen(s+1);
m=strlen(t+1);
getfail();
memset(ok,0,sizeof ok);
memset(C,0,sizeof C);
p = 0;
for(i=1;i<=n;i++) {
while(p && t[p+1]!=s[i]) p = fail[p];
p += (t[p+1]==s[i]);
if (p == m) ok[i]=true,ins(i,1);
}
while(q-->0) {
while(mode=getchar(),mode!='Q'&&mode!='C');
if (mode == 'Q') {
scanf("%d%d",&j,&k);
Query(j,k);
} else {
scanf("%d",&j);
while(c=getchar(),c<'!');
Change(j,c);
}
}
puts("");
}
int main() {
int T;
scanf("%d",&T);
while(T-->0) work();
return 0;
}