NOIP2017提高A组模拟10.6】Biology

题目

这里写图片描述

trie

暴力就是对于每个询问的T个字符串
第i个和第i+1个直接个从后暴力枚举每位是否相同,
但这个方法TLE
我们考虑是否可以用更快的方法来求出两个字符串的最长公共后缀。
我们把所有的字符串从后往前扔进trie中,搞个lca就可以了,最长公共后缀就是lca的深度。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
const int maxlongint=2147483647;
const int mo=1e9+7;
const int N=1000105;
using namespace std;
struct trie
{
    int a[27],deep;
}tr[N];
int n,m,ans,rt[N],tot,len,le,g[N][23],lo;
char s[N];
int lca(int x,int y)
{
    if(tr[x].deep>tr[y].deep) swap(x,y);
    for(int j=lo;j>=0;j--)
        if(tr[g[y][j]].deep>=tr[x].deep) y=g[y][j];
    if(x==y) return tr[x].deep;
    for(int j=lo;j>=0;j--)
        if(g[y][j]!=g[x][j]) x=g[x][j],y=g[y][j];
    return tr[g[x][0]].deep;
}
int put(int x)
{
    int now=1;
    for(int i=x;i>=1;i--)
    {
        int t=tr[now].a[s[i]-'a'];
        if(t) now=t;
        else 
        {
            tr[tr[now].a[s[i]-'a']=++tot].deep=tr[now].deep+1,g[tot][0]=now,now=tot;
            for(int j=1;j<=lo;j++) g[now][j]=g[g[now][j-1]][j-1];
        }
    }
    return now;
}
int main()
{
    scanf("%d%d",&n,&m);
    lo=20;
    tr[++tot].deep=1;
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        int len=strlen(s+1);
        rt[i]=put(len);
    }
    for(int i=1;i<=m;i++)
    {
        int t;
        scanf("%d",&t);
        if(t==1)
        {
            scanf("%s",s+1);
            int len=strlen(s+1);
            rt[++n]=put(len);
        }
        else
        {
            int T,TU[12],ans=maxlongint;
            scanf("%d",&T);
            for(int j=1;j<=T;j++) scanf("%d",&TU[j]);
            for(int j=1;j<=T-1;j++) ans=min(lca(rt[TU[j]],rt[TU[j+1]]),ans);
            printf("%d\n",ans-1);
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/chen1352/p/9079623.html