Query on a string 暴力+树状数组

本文介绍了一种处理字符串匹配更新问题的高效算法。该算法能在O(Q*|T|^2*logn)的时间复杂度内完成Q次操作,包括修改母串中的字符及查询子串在母串中出现的次数。通过使用树状数组维护字符串匹配状态,使得算法能够快速响应修改与查询操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

点击打开链接

题意:给出母串s和字符串T,Q次操作.

操作1:把s的第i个字符修改为ch.
操作2:询问s[i,j]中,T出现了多少次?
Q,|s|<=1e5.|T|<=10.

令f[i]标记s[i]结尾能否匹配字符串T.对于查询操作只要query(l+len2-1,r)
因为还有修改操作,又因为|T|<=10 修改s中的一个字符 最多只有|T|个位置f[i]变化,暴力修改f[i].

f[i]的前缀和是变化的 用树状数组来维护即可.O(Q*|T|^2*logn). 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
const int N=1e5+20;
char s[N],t[N];
int c[N],f[N],fail[N],len1,len2;
int lowbit(int x){return x&(-x);}
void update(int x,int val)
{
	for(int i=x;i<N;i+=lowbit(i))
		c[i]+=val;	
}
int query(int x)
{
	int res=0;
	for(int i=x;i>0;i-=lowbit(i))
		res+=c[i];
	return res;
}
void getfail(char *b)  
{  
    int i=0,j=-1;  
    int len=strlen(b);  
    fail[0]=-1;  
    while(i<len)  
    {  
        while(j!=-1&&b[i]!=b[j]) j=fail[j];  
        if(b[++i]==b[++j]) fail[i]=j;  
        else fail[i]=j;  
    }  
}  
void kmp(char *a,char *b)   
{  
    int i=0,j=0;  
    getfail(b);  
    int lena=strlen(a),lenb=strlen(b);  
    while(i<lena)  
    {  
        while(j!=-1&&a[i]!=b[j]) j=fail[j];  
        i++,j++;  
        if(j>=lenb)   
        {  
            f[i]=1;  
            update(i,1);  
        }  
    }  
}  
  
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		memset(f,0,sizeof(f));
		memset(c,0,sizeof(c));
		int l,r,Q;
		char c,op[5];
		scanf("%d%s%s",&Q,s+1,t+1);
		len1=strlen(s+1),len2=strlen(t+1);
		kmp(s+1,t+1);
		while(Q--)
		{
			scanf("%s",op);
			if(op[0]=='Q')
			{
				scanf("%d%d",&l,&r);
				printf("%d\n",query(r)-query(l+len2-2));	
			}
			else
			{
				scanf("%d %c",&l,&c);
				s[l]=c;
				for(int i=l;i>=max(1,l-len2+1);i--)
				{
					bool flag=true;
					for(int k=1;k<=len2;k++)
					{
						if(s[i+k-1]!=t[k])
						{
							flag=false;
							break;
						}
					}
					int pos=i+len2-1;
					bool mk=f[pos]?true:false;
					if(!mk&&flag)
						f[pos]=1,update(pos,1);
					else if(mk&&(!flag))
						f[pos]=0,update(pos,-1);
				}
			}
		}
		printf("\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值