您的位置:首页 > 理论基础 > 计算机网络

2017 ACM-ICPC乌鲁木齐网络赛 G. Query on a string(KMP+树状数组)

2017-09-09 18:14 597 查看
题目链接:https://www.jisuanke.com/contest/870

题意:

给出两个字符串S和T,Q次操作:①C a b表示将第a个字符改为b;②Q l r表示T在S的子串[l, r]中共出现多少次

其中|S|<=100000,|T|<=10,Q<=100000

思路:

若S串的子串[x-|T|+1, x]和T串完美匹配,那么flag[x]==1,否则flag[x]==0,sum[]是flag[]的前缀和

这样每次查询区间[l, r]答案就是sum[r]-sum[l+|T|-2],注意特判r<l+|T|-2的情况

用树状数组维护就好

又因为|T|<10,所以每次修改影响的范围很小,可以直接暴力

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define LL long long
char str[100005], jud[100005];
int n, nj[100005], ns[100005];
LL tre[100005];
void Update(int x, int val)
{
while(x<=n)
{
tre[x] += val;
x += x&-x;
}
}
LL Query(int x)
{
LL sum = 0;
while(x)
{
sum += tre[x];
x -= x&-x;
}
return sum;
}
int main(void)
{
char ch[15];
int T, Q, m, p, q, L, R;
scanf("%d", &T);
while(T--)
{
scanf("%d%s%s", &Q, str+1, jud+1);
n = strlen(str+1);
m = strlen(jud+1);
p = 0, q = 1;
memset(nj, 0, sizeof(nj));
memset(tre, 0, sizeof(tre));
memset(ns, 0, sizeof(ns));
while(q<=m)
{
if(p==0 || jud[p]==jud[q])
{
p++, q++;
if(jud[p]==jud[q])
nj[q] = nj[p];
else
nj[q] = p;
}
else
p = nj[p];
}
p = q = 1;
while(p<=n)
{
while(str[p]!=jud[q] && q>=1)
q = nj[q];
if(q==0)
{
ns[p] = 0;
p++, q++;
continue;
}
ns[p++] = q++;
if(q==m+1)
{
Update(p-1, 1);
q = nj[q];
}
}
while(Q--)
{
scanf("%s", ch);
if(ch[0]=='Q')
{
scanf("%d%d", &L, &R);
if(L+m-1>R)
printf("0\n");
else
printf("%lld\n", Query(R)-Query(L+m-2));
}
else
{
scanf("%d%s", &R, ch);
p = max(R-15, 0), q = ns[p];
str[R] = ch[0];
while(p<=R+15 && p<=n)
{
while(str[p]!=jud[q] && q>=1)
q = nj[q];
if(q==0)
{
if(ns[p]==m)
Update(p, -1);
ns[p] = 0;
p++, q++;
continue;
}
if(ns[p]==m)
Update(p, -1);
ns[p++] = q++;
if(q==m+1)
{
Update(p-1, 1);
q = nj[q];
}
}
}
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐