[CF914F] Substrings in a String

\(\text{Problem}:\)Substrings in a String

\(\text{Solution}:\)

考虑分块,对每个块建出后缀自动机。

修改:暴力重建 \(i\) 所在块的 \(\text{SAM}\)

查询:分类讨论处理。

  • \(\lvert s\rvert> B\)\(B\) 为块长),则建出 \(s[l:r]\)\(\text{SAM}\)\(O(n)\) 暴力匹配。
  • \(\lvert s\rvert\leq B\),首先在每个块内暴力匹配 \(\text{SAM}\) 求出每个块内的答案。对于跨越两个块的答案可以暴力匹配(每两块之间要考虑的字符串长度小于 \(2\lvert s\rvert\))。

易知总时间复杂度为 \(O(n\sqrt {n})\)

一些优化:只在查询到整块时才对这个块建出 \(\text{SAM}\),可以用打标记实现。注意 \(\text{SAM}\) 每次重构时,新加结点才清空转移数组(优化很显著)。还得调调块长。\(\text{bitset}\) 吊着打

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=200010, B=810;
inline int read()
{
	int s=0; ri char ch=getchar();
	while(ch<'0'||ch>'9') { ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s;
} char inp[N],q[N];
int n,Q,blk,bl[N],tl[N],tr[N],tag[N];
struct SAM
{
	char s[B]; int Len;
	int link[B],len[B],ch[B][26],siz[B];
	int head[B],maxE; struct Edge { int nxt,to; }e[B];
	inline void Add(int u,int v) { e[++maxE].nxt=head[u]; head[u]=maxE; e[maxE].to=v; }
	int tot,lst;
	inline SAM() { tot=lst=1; link[1]=len[1]=0; memset(ch[1],0,sizeof(ch[1])); }
	inline void Extend(int c)
	{
		int now=++tot; memset(ch[now],0,sizeof(ch[now]));
		int p=lst;
		siz[now]=1;
		while(p && !ch[p][c]) ch[p][c]=now, p=link[p];
		len[now]=len[lst]+1;
		if(!p) { lst=now, link[now]=1; return; }
		int q=ch[p][c];
		if(len[q]==len[p]+1) link[now]=q;
		else
		{
			int nq=++tot;
			len[nq]=len[p]+1;
			memcpy(ch[nq],ch[q],sizeof(ch[q]));
			link[nq]=link[q];
			link[q]=link[now]=nq;
			while(p && ch[p][c]==q) ch[p][c]=nq, p=link[p];
		}
		lst=now;
	}
	void DFS(int x)
	{
		for(ri int i=head[x];i;i=e[i].nxt)
		{
			int v=e[i].to;
			DFS(v);
			siz[x]+=siz[v];
		}
	}
	inline void Build()
	{
		for(ri int i=1;i<=tot;i++) head[i]=siz[i]=0;
		tot=lst=1, maxE=0, memset(ch[1],0,sizeof(ch[1]));
		for(ri int i=1;i<=Len;i++) Extend(s[i]-'a');
		for(ri int i=2;i<=tot;i++) Add(link[i],i);
		DFS(1);
	}
	inline int Ask(char *q,int L)
	{
		int sta=1;
		for(ri int i=0;i<L;i++)
		{
			int p=q[i]-'a';
			sta=ch[sta][p];
			if(!sta) break;
		}
		if(!sta) return 0;
		return siz[sta];
	}
}f[B];
struct BSAM
{
	char s[N]; int Len;
	int link[N],len[N],ch[N][26],siz[N];
	int head[N],maxE; struct Edge { int nxt,to; }e[N];
	inline void Add(int u,int v) { e[++maxE].nxt=head[u]; head[u]=maxE; e[maxE].to=v; }
	int tot,lst;
	inline SAMM() { tot=lst=1; link[1]=len[1]=0; memset(ch[1],0,sizeof(ch[1])); }
	inline void Extend(int c)
	{
		int now=++tot; memset(ch[now],0,sizeof(ch[now]));
		int p=lst;
		siz[now]=1;
		while(p && !ch[p][c]) ch[p][c]=now, p=link[p];
		len[now]=len[lst]+1;
		if(!p) { lst=now, link[now]=1; return; }
		int q=ch[p][c];
		if(len[q]==len[p]+1) link[now]=q;
		else
		{
			int nq=++tot;
			len[nq]=len[p]+1;
			memcpy(ch[nq],ch[q],sizeof(ch[q]));
			link[nq]=link[q];
			link[q]=link[now]=nq;
			while(p && ch[p][c]==q) ch[p][c]=nq, p=link[p];
		}
		lst=now;
	}
	void DFS(int x)
	{
		for(ri int i=head[x];i;i=e[i].nxt)
		{
			int v=e[i].to;
			DFS(v);
			siz[x]+=siz[v];
		}
	}
	inline void Build()
	{
		for(ri int i=1;i<=tot;i++) head[i]=siz[i]=0;
		tot=lst=1, maxE=0, memset(ch[1],0,sizeof(ch[1]));
		for(ri int i=1;i<=Len;i++) Extend(s[i]-'a');
		for(ri int i=2;i<=tot;i++) Add(link[i],i);
		DFS(1);
	}
	inline int Ask(char *q,int L)
	{
		int sta=1;
		for(ri int i=0;i<L;i++)
		{
			int p=q[i]-'a';
			sta=ch[sta][p];
			if(!sta) break;
		}
		if(!sta) return 0;
		return siz[sta];
	}
}g;
signed main()
{
	scanf("%s",inp+1);
	n=strlen(inp+1);
	blk=400;
	for(ri int i=1;i<=n;i++) bl[i]=(i-1)/blk+1;
	for(ri int i=1;i<=bl[n];i++)
	{
		tl[i]=(i-1)*blk+1, tr[i]=min(i*blk,n);
		f[i].Len=tr[i]-tl[i]+1;
		for(ri int j=tl[i];j<=tr[i];j++) f[i].s[j-tl[i]+1]=inp[j];
		tag[i]=1;
	}
	Q=read();
	for(ri int i=1;i<=Q;i++)
	{
		int opt=read();
		if(opt==1)
		{
			int x=read();
			scanf("%s",q);
			int L=bl[x];
			f[L].s[x-tl[L]+1]=q[0];
			inp[x]=q[0];
			tag[L]=1;
		}
		else
		{
			int l,r;
			l=read(), r=read();
			scanf("%s",q);
			int len=strlen(q);
			int L=bl[l], R=bl[r];
			if(len>blk||L==R)
			{
				g.Len=r-l+1;
				for(ri int j=l;j<=r;j++) g.s[j-l+1]=inp[j];
				g.Build();
				printf("%d\n",g.Ask(q,len));
			}
			else
			{
				int ans=0;
				for(ri int j=L+1;j<R;j++)
				{
					if(tag[j]) f[j].Build(), tag[j]=0;
					ans+=f[j].Ask(q,len);
				}
				g.Len=tr[L]-l+1;
				for(ri int j=l;j<=tr[L];j++) g.s[j-l+1]=inp[j];
				g.Build();
				ans+=g.Ask(q,len);
				if(L!=R)
				{
					g.Len=r-tl[R]+1;
					for(ri int j=tl[R];j<=r;j++) g.s[j-tl[R]+1]=inp[j];
					g.Build();
					ans+=g.Ask(q,len);
				}
				if(L!=R && len>=2)
				{
					for(ri int j=L;j<R;j++)
					{
						int lef=max(l,tr[j]-len+2);
						int rig=min(r,tl[j+1]+len-2);
						if(bl[lef]==j && bl[rig]==j+1)
						{
							g.Len=rig-lef+1;
							for(ri int k=lef;k<=rig;k++) g.s[k-lef+1]=inp[k];
							g.Build();
							ans+=g.Ask(q,len);
						}
					}
				}
				printf("%d\n",ans);
			}
		}
	}
	return 0;
}
posted @ 2021-05-01 20:50  zkdxl  阅读(58)  评论(1编辑  收藏  举报