最长公共前缀(lca+trie树)

问题描述

给出一些串,多组询问求两个串的最长公共前缀。字符串总长 < 10^6。

输入格式

第一行一个整数n,表示字符串的个数。

接下来n行,每行一个字符串(字符串不含空格)。

第n+2行一个整数m,表示询问总数。

接下来m行,每行两个整数a,b,表示询问第a个字符串和第b个字符串的最长公共前缀的长度。

输出格式

输出共m行,对于每个询问输出最长的公共前缀的长度

输入样例

5
abcdef
abcd
acd
cade
abcdef
4
1 2
2 3
1 5
3 4

输出样例

4
1
6
0

限制与约定

1<= m < 10^6

时间限制:1s

空间限制:256MB

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 1000000 + 10 ;
int n,ch[maxn][30],val[maxn],cnt,m;
int f[maxn][31],Dep[maxn];
string str[30010];
void dfs(int u,int fa)
{
    Dep[u]=Dep[fa]+1;
    for(int i=0;i<=29;i++) f[u][i+1]=f[f[u][i]][i];
    for(int i=0;i<=26;i++)
    {
        int v = ch[u][i];
        if(!v) continue;
        f[v][0]=u;
        dfs(v,u);
    }
}
void insert(int pos)
{
    int len = str[pos].length(),u=0;
    for(int i=0;i<len;i++)
    {
        int x = str[pos][i]-'a';
        if(!ch[u][x]) ch[u][x]=++cnt;
        u=ch[u][x];
    }
    val[pos]=u;
}
int LCA(int x,int y)
{
    if(Dep[x]<Dep[y]) swap(x,y);
    for(int i=30;i>=0;i--)
    {
        if(Dep[f[x][i]]>=Dep[y]) x=f[x][i];
        if(x==y) return x;
    }
    for(int i=30;i>=0;i--)
        if(f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
    return f[x][0];
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>str[i];
        insert(i);
    }
    dfs(0,-1);
    cin>>m;
    for(int i=1,a,b;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        int lca=LCA(val[a],val[b]);
        printf("%d\n",Dep[lca]-1);
    }
    return 0;
}

 

posted @ 2019-06-18 20:20  寒方  阅读(1025)  评论(0编辑  收藏  举报