传送门
写法很显然,问题是怎么写。。
哈希是把长度为1~n的全部哈希出来,因为树的深度不超过
n
n
n嘛。
哈希出左到右和右到左两个方向。把模式串不断重复即可。然后就好写了。
注意一个去掉
k
∗
m
k*m
k∗m的长度为
d
d
d的链,需要匹配的是长度为
m
−
d
+
1
m-d+1
m−d+1的。因为当前的重心相当于是一个共用的字符。
不要
m
e
m
s
e
t
memset
memset,还有
s
i
z
siz
siz小于
m
m
m的时候就不用搜下去了。
#include<bits/stdc++.h>
#define cs const
#define re register
#define ull unsigned long long
cs int N=1e6+10,M=1e6+10;
cs ull base=131;
namespace IO{
cs int Rlen=1<<22|1;
char buf[Rlen],*p1,*p2;
inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}
template<typename T>
inline T get(){
char ch=gc();T x=0;
while(!isdigit(ch)) ch=gc();
while(isdigit(ch)) x=((x+(x<<2))<<1)+(ch^48),ch=gc();
return x;
}
inline int gi(){return get<int>();}
inline int ga(){
char ch=gc();
while(!isalpha(ch)) ch=gc();
return ch-'A';
}
}
using IO::gi;
using IO::ga;
inline void Max(int &a,int b){if(a<b)a=b;}
inline void Min(int &a,int b){if(a>b)a=b;}
int T,n,m,u,v,s[N],t[N];//s 匹配,t 树上节点。
ull hash_lft[N],hash_rgt[N],Pow[N];int pre[N],suf[N];
int Head[N],Next[N<<1],V[N<<1],cnt=0;
int root,siz[N],vis[N],mx[N],SIZ;
inline void add(int u,int v){Next[++cnt]=Head[u],V[cnt]=v,Head[u]=cnt;}
inline void init(){
memset(Head,0,sizeof Head),cnt=0;
memset(vis,0,sizeof vis);
}
inline void getroot(int u,int f){
mx[u]=0,siz[u]=1;
for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]])
if((v!=f)&&(!vis[v])) getroot(v,u),Max(mx[u],siz[v]),siz[u]+=siz[v];
Max(mx[u],SIZ-siz[u]);if(mx[u]<mx[root]) root=u;
}
int st_suf[N],top_suf=0;
int st_pre[N],top_pre=0;
inline int calc(int u,int f,int dep,ull state,int ret=0){
int d=(dep-1)%m+1;
if(state==hash_lft[dep]) ret+=suf[m-d+1],st_pre[++top_pre]=d;
if(state==hash_rgt[dep]) ret+=pre[m-d+1],st_suf[++top_suf]=d;
for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]])
if((v!=f)&&(!vis[v])) ret+=calc(v,u,dep+1,state*base+t[v]);
return ret;
}
inline int getans(int u,int f,int ret=0,int len=0){
pre[1]=(s[1]==t[u]),suf[1]=(s[m]==t[u]);
for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]]) if((v!=f)&&(!vis[v])){
ret+=calc(v,u,2,base*t[u]+t[v]);
while(top_pre) Max(len,st_pre[top_pre]),++pre[st_pre[top_pre--]];
while(top_suf) Max(len,st_suf[top_suf]),++suf[st_suf[top_suf--]];
}for(int re i=1;i<=len;++i) pre[i]=suf[i]=0;
return ret;
}
inline int dfs(int u,int ret=0){
vis[u]=1,ret+=getans(u,0);
for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]])
if(!vis[v]&&siz[v]>=m) SIZ=siz[v],root=0,getroot(v,u),ret+=dfs(root);
return ret;
}
int main(){
// freopen("2842.in","r",stdin);
T=gi(),Pow[0]=1;
for(int re i=1;i<N;++i) Pow[i]=Pow[i-1]*base;
while(T--){
init(),n=gi(),m=gi();
for(int re i=1;i<=n;++i) t[i]=ga();
for(int re i=1;i< n;++i) u=gi(),v=gi(),add(u,v),add(v,u);
for(int re i=1;i<=m;++i) s[i]=ga();
for(int re i=1;i<=n;++i) hash_lft[i]=hash_lft[i-1]+s[(i-1)%m+1]*Pow[i-1];
for(int re i=1;i<=n;++i) hash_rgt[i]=hash_rgt[i-1]+s[m-(i-1)%m]*Pow[i-1];
SIZ=n,mx[root=0]=n,getroot(1,0),printf("%d\n",dfs(root));
}
}
本文深入探讨了一种高效的树状结构中字符串匹配算法,利用哈希技术进行快速定位和匹配,特别适用于处理大规模数据集中的模式串搜索。文章详细介绍了算法的实现步骤,包括如何构造哈希值、优化搜索过程以及避免重复计算等关键环节。
5万+

被折叠的 条评论
为什么被折叠?



