HDU6138:Fleet of the Eternal Throne(后缀自动机)

传送门

题解:
每次询问时对询问的两个串xxyy分别做:
建后缀自动机,求出每个串是这个串的子串的最长前缀。
每个串对xxyy的答案取min,所有串的答案取max即可。
时间复杂度O(nm)O(nm)

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
char ch[N];
int n,m,bg[N],ed[N],len;
int l[N*2],son[N*2][26],mx[N*2],ok[N*2],link[N*2],last,tot;
inline void sam_init() {
    for(int i=1;i<=tot;i++)
        memset(son[i],0,sizeof(son[i])), mx[i]=0, ok[i]=0;
    last=tot=1;
}
inline void extend(int c) {
    int p=++tot; l[p]=l[last]+1;
    while(last && !son[last][c]) 
        son[last][c]=p, last=link[last];
    if(!last) link[p]=1;
    else {
        int q=son[last][c];
        if(l[q]==l[last]+1) link[p]=q;
        else {
            int np=++tot; link[np]=link[q]; l[np]=l[last]+1; 
            memcpy(son[np],son[q],sizeof(son[np]));
            link[q]=link[p]=np;
            while(last && son[last][c]==q) 
                son[last][c]=np, last=link[last];
        }
    } last=p;
}
inline int upt_ok(int id) {
    int p=1,i;
    for(i=bg[id];i<=ed[id];i++) {
        int c=ch[i]-'a';
        if(!son[p][c]) break;
        p=son[p][c]; ok[p]=1;
    }
    return i-bg[id];
}
int ans[N];
inline void solve() {
    len=0;  scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        bg[i]=len+1;
        scanf("%s",ch+bg[i]);
        ed[i]=bg[i]+strlen(ch+bg[i])-1;
        len=ed[i];
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++) {
        int x,y; scanf("%d%d",&x,&y);
        sam_init();
        for(int j=bg[x];j<=ed[x];++j) extend(ch[j]-'a');
        for(int j=1;j<=n;j++) ans[j]=upt_ok(j);
        sam_init();
        for(int j=bg[y];j<=ed[y];++j) extend(ch[j]-'a');
        for(int j=1;j<=n;j++) ans[j]=min(ans[j],upt_ok(j));

        int rs=0;
        for(int j=1;j<=n;j++) rs=max(rs,ans[j]);
        printf("%d\n",rs);
    }
}
int main() {
    int T; scanf("%d",&T);
    l[0]=-1;
    for(int i=0;i<26;i++) 
        son[0][i]=1;
    while(T--) solve();
}
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页