Bzoj2434 阿狸的打字机

本文深入探讨了广义SAM(Suffix Automaton)的构建与应用,特别是在处理字符串匹配问题上的高效算法。通过离线询问和Fenwick树(Binary Indexed Tree)维护子树和的方式,实现了主串在另一个串中出现次数的快速查询。文章还强调了正确处理LCA(Lowest Common Ancestor)的重要性,以确保算法的时间复杂度。代码实例详细展示了如何在实际问题中应用这些理论。

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

纪念一次AC,水一篇blog

又是喜闻乐见的广义SAM题辣
题意:给一个trie,每次问询一个串在另一个串出现的次数
思路:建立广义SAM,离线所有询问,每次讲一个主串在fail树上的节点+1,处理询问就用fenwick维护子树和
这里注意,
1.广义SAM要用bfs建
2.每次从一个主串到下一个时,不要整个都减掉而是要在LCA处会和,这样复杂度就是对的
代码有点长但是很好打

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 200010
using namespace std;
struct fenwick{
	int w[N],n,v;
	inline void init(int c){ n=c; }
	inline void add(int x){ for(;x<=n;x+=x&-x) ++w[x]; }
	inline void dec(int x){ for(;x<=n;x+=x&-x) --w[x]; }
	inline int sum(int x){ for(v=0;x;x&=x-1) v+=w[x]; return v; }
} w;
int h[N],cnt=1,d[N],l[N],r[N],clk,f[N];
int s[N][26],lst[N],v[N],n,m,tot=1,nc,q[N],A[N];
struct edge{ int v,nt; } G[N<<1];
namespace SAM{
	int s[N][26],mx[N],f[N],cnt=1;
	inline int extend(int p,int c){
		int np=++cnt,q,nq;
		mx[np]=mx[p]+1;
		for(;p&&!s[p][c];p=f[p]) s[p][c]=np;
		if(!p){ f[np]=1; return np; }
		q=s[p][c];
		if(mx[q]==mx[p]+1) f[np]=q;
		else{
			nq=++cnt;
			mx[nq]=mx[p]+1;
			f[nq]=f[q]; f[q]=f[np]=nq;
			memcpy(s[nq],s[q],26<<2);
			for(;p&&s[p][c]==q;p=f[p]) s[p][c]=nq;
		}
		return np;
	}
	inline void dfs(int x){
		l[x]=++clk;
		for(int i=h[x];i;i=G[i].nt) dfs(G[i].v);
		r[x]=clk;
	}
	inline void buildTree(){
		for(int i=2;i<=cnt;++i){
			G[++::cnt]=(edge){i,h[f[i]]}; h[f[i]]=::cnt;
		}
		dfs(1);
	}
}
char S[N],*T;
struct V{ int x,y,r; } g[N];
inline bool cv(V a,V b){ return a.y<b.y; }
inline void Btrie(int x){
	if(!*T) return;
	if(*T=='B'){ ++T; return; } else
	if(*T=='P'){ v[++nc]=x; ++T; Btrie(x); }
	else{
		if(!s[x][*T-='a']) s[x][*T]=++tot;
		f[tot]=x; d[tot]=d[x]+1; Btrie(s[x][*T++]); Btrie(x);
	}
}
int main(){
	scanf("%s%d",S,&m);
	T=S; Btrie(1);
	int l=1,r=0; lst[q[++r]=1]=1;
	for(int x;l<=r;++l){
		x=q[l];
		for(int i=0;i<26;++i)
			if(s[x][i]){
				lst[s[x][i]]=SAM::extend(lst[x],i);
				q[++r]=s[x][i];
			}
	}
	SAM::buildTree(); w.init(SAM::cnt);
	for(int i=1;i<=m;++i) scanf("%d%d",&g[i].x,&g[i].y),g[i].r=i;
	sort(g+1,g+1+m,cv); v[0]=1;
	for(int x,y=1,i=1,j=1;i<=m;){
		while(j<=m && g[j].y==g[i].y) ++j;
		x=v[g[i].y]; y=v[g[i-1].y];
		while(d[x]>d[y]){
			w.add(::l[lst[x]]); x=f[x];
		}
		while(d[y]>d[x]){
			w.dec(::l[lst[y]]); y=f[y];
		}
		while(x!=y){
			w.add(::l[lst[x]]); x=f[x];
			w.dec(::l[lst[y]]); y=f[y];
		}
		for(;i<j;++i)
			A[g[i].r]=w.sum(::r[lst[v[g[i].x]]])-w.sum(::l[lst[v[g[i].x]]]-1);
	}
	for(int i=1;i<=m;++i) printf("%d\n",A[i]);
}

放个LaTeXLaTeXLaTeX版本的代码恶心人~
#include&lt;stdio.h&gt;\#include&lt;stdio.h&gt;#include<stdio.h>
#include&lt;string.h&gt;\#include&lt;string.h&gt;#include<string.h>
#include&lt;algorithm&gt;\#include&lt;algorithm&gt;#include<algorithm>
#define N 200010\#define\ N\ 200010#define N 200010
using namespace std;using\ namespace\ std;using namespace std;
struct fenwick{struct\ fenwick\{struct fenwick{
int w[N],n,v;\quad int\ w[N],n,v;int w[N],n,v;
inline void init(int c){ n=c; }\quad inline\ void\ init(int\ c)\{\ n=c;\ \}inline void init(int c){ n=c; }
inline void add(int x){ for(;x&lt;=n;x+=x&amp;−x) ++w[x]; }\quad inline\ void\ add(int\ x)\{\ for(;x&lt;=n;x+=x\&amp;-x)\ ++w[x];\ \}inline void add(int x){ for(;x<=n;x+=x&x) ++w[x]; }
inline void dec(int x){ for(;x&lt;=n;x+=x&amp;−x) −−w[x]; }\quad inline\ void\ dec(int\ x)\{\ for(;x&lt;=n;x+=x\&amp;-x)\ --w[x];\ \}inline void dec(int x){ for(;x<=n;x+=x&x) w[x]; }
inline int sum(int x){ for(v=0;x;x&amp;=x−1) v+=w[x]; return v; }\quad inline\ int\ sum(int\ x)\{\ for(v=0;x;x\&amp;=x-1)\ v+=w[x];\ return\ v;\ \}inline int sum(int x){ for(v=0;x;x&=x1) v+=w[x]; return v; }
} w;\}\ w;} w;
int h[N],cnt=1,d[N],l[N],r[N],clk,f[N];int\ h[N],cnt=1,d[N],l[N],r[N],clk,f[N];int h[N],cnt=1,d[N],l[N],r[N],clk,f[N];
int s[N][26],lst[N],v[N],n,m,tot=1,nc,q[N],A[N];int\ s[N][26],lst[N],v[N],n,m,tot=1,nc,q[N],A[N];int s[N][26],lst[N],v[N],n,m,tot=1,nc,q[N],A[N];
struct edge{ int v,nt; } G[N&lt;&lt;1];struct\ edge\{\ int\ v,nt;\ \}\ G[N&lt;&lt;1];struct edge{ int v,nt; } G[N<<1];
namespace SAM{namespace\ SAM\{namespace SAM{
int s[N][26],mx[N],f[N],cnt=1;\quad int\ s[N][26],mx[N],f[N],cnt=1;int s[N][26],mx[N],f[N],cnt=1;
inline int extend(int p,int c){\quad inline\ int\ extend(int\ p,int\ c)\{inline int extend(int p,int c){
int np=++cnt,q,nq;\quad \quad int\ np=++cnt,q,nq;int np=++cnt,q,nq;
mx[np]=mx[p]+1;\quad \quad mx[np]=mx[p]+1;mx[np]=mx[p]+1;
for(;p&amp;&amp;!s[p][c];p=f[p]) s[p][c]=np;\quad \quad for(;p\&amp;\&amp;!s[p][c];p=f[p])\ s[p][c]=np;for(;p&&!s[p][c];p=f[p]) s[p][c]=np;
if(!p){ f[np]=1; return np; }\quad \quad if(!p)\{\ f[np]=1;\ return\ np;\ \}if(!p){ f[np]=1; return np; }
q=s[p][c];\quad \quad q=s[p][c];q=s[p][c];
if(mx[q]==mx[p]+1) f[np]=q;\quad \quad if(mx[q]==mx[p]+1)\ f[np]=q;if(mx[q]==mx[p]+1) f[np]=q;
else{\quad \quad else\{else{
nq=++cnt;\quad \quad \quad nq=++cnt;nq=++cnt;
mx[nq]=mx[p]+1;\quad \quad \quad mx[nq]=mx[p]+1;mx[nq]=mx[p]+1;
f[nq]=f[q]; f[q]=f[np]=nq;\quad \quad \quad f[nq]=f[q];\ f[q]=f[np]=nq;f[nq]=f[q]; f[q]=f[np]=nq;
memcpy(s[nq],s[q],26&lt;&lt;2);\quad \quad \quad memcpy(s[nq],s[q],26&lt;&lt;2);memcpy(s[nq],s[q],26<<2);
for(;p&amp;&amp;s[p][c]==q;p=f[p]) s[p][c]=nq;\quad \quad \quad for(;p\&amp;\&amp;s[p][c]==q;p=f[p])\ s[p][c]=nq;for(;p&&s[p][c]==q;p=f[p]) s[p][c]=nq;
}\quad \quad \}}
return np;\quad \quad return\ np;return np;
}\quad \}}
inline void dfs(int x){\quad inline\ void\ dfs(int\ x)\{inline void dfs(int x){
l[x]=++clk;\quad \quad l[x]=++clk;l[x]=++clk;
for(int i=h[x];i;i=G[i].nt) dfs(G[i].v);\quad \quad for(int\ i=h[x];i;i=G[i].nt)\ dfs(G[i].v);for(int i=h[x];i;i=G[i].nt) dfs(G[i].v);
r[x]=clk;\quad \quad r[x]=clk;r[x]=clk;
}\quad \}}
inline void buildTree(){\quad inline\ void\ buildTree()\{inline void buildTree(){
for(int i=2;i&lt;=cnt;++i){\quad \quad for(int\ i=2;i&lt;=cnt;++i)\{for(int i=2;i<=cnt;++i){
G[++::cnt]=(edge){i,h[f[i]]}; h[f[i]]=::cnt;\quad \quad \quad G[++::cnt]=(edge)\{i,h[f[i]]\};\ h[f[i]]=::cnt;G[++::cnt]=(edge){i,h[f[i]]}; h[f[i]]=::cnt;
}\quad \quad \}}
dfs(1);\quad \quad dfs(1);dfs(1);
}\quad \}}
}\}}
char S[N],∗T;char\ S[N],*T;char S[N],T;
struct V{ int x,y,r; } g[N];struct\ V\{\ int\ x,y,r;\ \}\ g[N];struct V{ int x,y,r; } g[N];
inline bool cv(V a,V b){ return a.y&lt;b.y; }inline\ bool\ cv(V\ a,V\ b)\{\ return\ a.y&lt;b.y;\ \}inline bool cv(V a,V b){ return a.y<b.y; }
inline void Btrie(int x){inline\ void\ Btrie(int\ x)\{inline void Btrie(int x){
if(!∗T) return;\quad if(!*T)\ return;if(!T) return;
if(∗T==′B′){ ++T; return; } else\quad if(*T==&#x27;B&#x27;)\{\ ++T;\ return;\ \}\ elseif(T==B){ ++T; return; } else
if(∗T==′P′){ v[++nc]=x; ++T; Btrie(x); }\quad if(*T==&#x27;P&#x27;)\{\ v[++nc]=x;\ ++T;\ Btrie(x);\ \}if(T==P){ v[++nc]=x; ++T; Btrie(x); }
else{\quad else\{else{
if(!s[x][∗T−=′a′]) s[x][∗T]=++tot;\quad \quad if(!s[x][*T-=&#x27;a&#x27;])\ s[x][*T]=++tot;if(!s[x][T=a]) s[x][T]=++tot;
f[tot]=x; d[tot]=d[x]+1; Btrie(s[x][∗T++]); Btrie(x);\quad \quad f[tot]=x;\ d[tot]=d[x]+1;\ Btrie(s[x][*T++]);\ Btrie(x);f[tot]=x; d[tot]=d[x]+1; Btrie(s[x][T++]); Btrie(x);
}\quad \}}
}\}}
int main(){int\ main()\{int main(){
scanf(&quot;%s%d&quot;,S,&amp;m);\quad scanf(&quot;\%s\%d&quot;,S,\&amp;m);scanf("%s%d",S,&m);
T=S; Btrie(1);\quad T=S;\ Btrie(1);T=S; Btrie(1);
int l=1,r=0; lst[q[++r]=1]=1;\quad int\ l=1,r=0;\ lst[q[++r]=1]=1;int l=1,r=0; lst[q[++r]=1]=1;
for(int x;l&lt;=r;++l){\quad for(int\ x;l&lt;=r;++l)\{for(int x;l<=r;++l){
x=q[l];\quad \quad x=q[l];x=q[l];
for(int i=0;i&lt;26;++i)\quad \quad for(int\ i=0;i&lt;26;++i)for(int i=0;i<26;++i)
if(s[x][i]){\quad \quad \quad if(s[x][i])\{if(s[x][i]){
lst[s[x][i]]=SAM::extend(lst[x],i);\quad \quad \quad \quad lst[s[x][i]]=SAM::extend(lst[x],i);lst[s[x][i]]=SAM::extend(lst[x],i);
q[++r]=s[x][i];\quad \quad \quad \quad q[++r]=s[x][i];q[++r]=s[x][i];
}\quad \quad \quad \}}
}\quad \}}
SAM::buildTree(); w.init(SAM::cnt);\quad SAM::buildTree();\ w.init(SAM::cnt);SAM::buildTree(); w.init(SAM::cnt);
for(int i=1;i&lt;=m;++i) scanf(&quot;%d%d&quot;,&amp;g[i].x,&amp;g[i].y),g[i].r=i;\quad for(int\ i=1;i&lt;=m;++i)\ scanf(&quot;\%d\%d&quot;,\&amp;g[i].x,\&amp;g[i].y),g[i].r=i;for(int i=1;i<=m;++i) scanf("%d%d",&g[i].x,&g[i].y),g[i].r=i;
sort(g+1,g+1+m,cv); v[0]=1;\quad sort(g+1,g+1+m,cv);\ v[0]=1;sort(g+1,g+1+m,cv); v[0]=1;
for(int x,y=1,i=1,j=1;i&lt;=m;){\quad for(int\ x,y=1,i=1,j=1;i&lt;=m;)\{for(int x,y=1,i=1,j=1;i<=m;){
while(j&lt;=m &amp;&amp; g[j].y==g[i].y) ++j;\quad \quad while(j&lt;=m\ \&amp;\&amp;\ g[j].y==g[i].y)\ ++j;while(j<=m && g[j].y==g[i].y) ++j;
x=v[g[i].y]; y=v[g[i−1].y];\quad \quad x=v[g[i].y];\ y=v[g[i-1].y];x=v[g[i].y]; y=v[g[i1].y];
while(d[x]&gt;d[y]){\quad \quad while(d[x]&gt;d[y])\{while(d[x]>d[y]){
w.add(::l[lst[x]]); x=f[x];\quad \quad \quad w.add(::l[lst[x]]);\ x=f[x];w.add(::l[lst[x]]); x=f[x];
}\quad \quad \}}
while(d[y]&gt;d[x]){\quad \quad while(d[y]&gt;d[x])\{while(d[y]>d[x]){
w.dec(::l[lst[y]]); y=f[y];\quad \quad \quad w.dec(::l[lst[y]]);\ y=f[y];w.dec(::l[lst[y]]); y=f[y];
}\quad \quad \}}
while(x!=y){\quad \quad while(x!=y)\{while(x!=y){
w.add(::l[lst[x]]); x=f[x];\quad \quad \quad w.add(::l[lst[x]]);\ x=f[x];w.add(::l[lst[x]]); x=f[x];
w.dec(::l[lst[y]]); y=f[y];\quad \quad \quad w.dec(::l[lst[y]]);\ y=f[y];w.dec(::l[lst[y]]); y=f[y];
}\quad \quad \}}
for(;i&lt;j;++i)\quad \quad for(;i&lt;j;++i)for(;i<j;++i)
A[g[i].r]=w.sum(::r[lst[v[g[i].x]]])−w.sum(::l[lst[v[g[i].x]]]−1);\quad \quad \quad A[g[i].r]=w.sum(::r[lst[v[g[i].x]]])-w.sum(::l[lst[v[g[i].x]]]-1);A[g[i].r]=w.sum(::r[lst[v[g[i].x]]])w.sum(::l[lst[v[g[i].x]]]1);
}\quad \}}
for(int i=1;i&lt;=m;++i) printf(&quot;%d\n&quot;,A[i]);\quad for(int\ i=1;i&lt;=m;++i)\ printf(&quot;\%d\backslash n&quot;,A[i]);for(int i=1;i<=m;++i) printf("%d\n",A[i]);
}\}}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值