题意:
给一个<=1e5的主串,一个<=10的匹配串,n次询问或操作,询问主串的[l, r]区间内与匹配串能匹配的个数(可重叠),操作给定一个位置pos和字符ch,将s[pos]改为ch。
思路:
由于匹配串长度很小,完全可以暴力去做,主串中与匹配串匹配的子串只有起点位置有值,然后通过树状数组维护区间和即可,不过查询时要注意一个小判断,区间有可能不足匹配串的长度。更新时,暴力去更新,改变一个字符,只会影响其前面少于十个位置,其后面少于十个位置。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
char s[maxn], p[15], mk1, mk2;
int a[maxn], tree[maxn];
int t, n, len1, len2, x, y;
int lowbit(int x){return x&(-x);}
void update(int k, int val)
{
while(k <= len1)
{
tree[k] += val;
k += lowbit(k);
}
}
int query(int k)
{
int ans = 0;
while(k)
{
ans += tree[k];
k -= lowbit(k);
}
return ans;
}
void init()
{
len1 = strlen(s+1);
len2 = strlen(p+1);
memset(tree, 0, sizeof tree);
for(int i = 1; i+len2-1 <= len1; ++i)
{
int t = 1;
while(t <= len2 && s[i+t-1] == p[t]) ++t;
a[i] = (t > len2);
update(i, a[i]);
}
}
int main()
{
//freopen("in.txt", "r", stdin);
for(scanf("%d", &t); t--;)
{
scanf("%d", &n);
scanf("%s", s+1);
scanf("%s", p+1);
init();
while(n--)
{
scanf(" %c %d", &mk1, &x);
if(mk1 == 'C')
{
scanf(" %c", &mk2);
if(s[x] == mk2) continue;
s[x] = mk2;
int st = x-len2+1, ed = x+len2-1;
if(st < 1) st = 1;
if(ed > len1) ed = len1;
for(int i = st; i <= ed && i+len2-1 <= len1; ++i)
{
int t = 1;
while(t <= len2 && s[i+t-1] == p[t]) ++t;
int chg = (t > len2);
if(a[i]) a[i] = 0, update(i, -1);
if(chg) a[i] = 1, update(i, 1);
}
}
else
{
scanf("%d", &y);
int ans = 0;
if(y-len2+1 >= x)
printf("%d\n", query(y-len2+1)-query(x-1));
else puts("0");
}
}
puts("");
}
return 0;
}
继续加油~