【JZOJ5397】Biology

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);
        }
    }
}
posted @ 2017-10-06 21:16  sadstone  阅读(37)  评论(0编辑  收藏  举报