Description
Solution
听说这题暴力能过
一个简便的做法是对于每个串从后往前扔进字典树上,对于一个查询,就是求这些串的开头节点的lca的深度。
还有一种做法是记录每个字符串的每个后缀的哈希值,然后比较两个后缀就可以O(1)判断,于是对于两个串,二分最大的长度即可。
Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 100010
#define inf 2147483647
using namespace std;
char s[N/10];
int tr[N*10][26];
int fa[N*10][21],dep[N*10];
int tot=1;
int fr[N];
int work(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
fd(i,20,0) if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
if(u==v) return dep[u]-1;
fd(i,20,0) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
return dep[fa[u][0]]-1;
}
void add(int x){
fo(i,1,20) fa[x][i]=fa[fa[x][i-1]][i-1];
dep[x]=dep[fa[x][0]]+1;
}
int main()
{
freopen("biology.in","r",stdin);
freopen("biology.out","w",stdout);
int n,m;
scanf("%d %d",&n,&m);
dep[1]=1;
fo(i,1,n)
{
scanf("%s",s+1);
int l=strlen(s+1),now=1;
fd(j,l,1)
{
int c=s[j]-'a';
if(!tr[now][c]) tr[now][c]=++tot,fa[tot][0]=now,add(tot);
int v=tr[now][c];
now=v;
}
fr[i]=now;
}
while(m--)
{
int op;
scanf("%d",&op);
if(op==1)
{
scanf("%s",s+1);
int l=strlen(s+1),now=1;
fd(j,l,1)
{
int c=s[j]-'a';
if(!tr[now][c]) tr[now][c]=++tot,fa[tot][0]=now,add(tot);
int v=tr[now][c];
now=v;
}
fr[++n]=now;
}
else
{
int T,o1,o2;
scanf("%d %d",&T,&o1);
int ans=inf;
fo(i,1,T-1)
{
scanf("%d",&o2);
ans=min(ans,work(fr[o1],fr[o2]));
o2=o1;
}
printf("%d\n",ans);
}
}
}