POJ 3294 Life Forms(广义后缀自动机)

给定(n)个串,求在一半以上的串中出现过的最长公共子串


(n)个串建广义后缀自动机,用树状数组统计(parent)树上每个节点子树包含的串的个数,之后遍历一遍求出最长公共子串长度,并标记相应节点,之后根据长度和标记在(DAG)(dfs)即可

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<vector>
using namespace std;
typedef long long ll;
const int Maxn=200010;
vector<int>g[Maxn];
struct Q{
    int id,l,r;
}ask[Maxn];
int n;
struct Suffix_Automata{
    int maxlen[Maxn], trans[Maxn][26], link[Maxn], Size;
    vector<int>sz[Maxn];
    void clr(int x){
        maxlen[x]=link[x]=0;
        memset(trans[x],0,sizeof(trans[x]));
        sz[x].clear();
    }
	void init(){
        Size=1;
        clr(1);
    }
    inline int insert(int ch, int last,int id){
        if (trans[last][ch]){
            int p = last, x = trans[p][ch];
            if (maxlen[p] + 1 == maxlen[x]) {sz[x].push_back(id);return x;}
            else{
                int y = ++Size;
                clr(y);
                maxlen[y] = maxlen[p] + 1;
                for (int i = 0; i < 26; ++i)
                    trans[y][i] = trans[x][i];
                while (p && trans[p][ch] == x)
                    trans[p][ch] = y, p = link[p];
                link[y] = link[x], link[x] = y;
                sz[y].push_back(id);
                return y;
            }
        }
        int z = ++Size, p = last;
        clr(z);
        sz[z].push_back(id);
        maxlen[z] = maxlen[last] + 1;
        while (p && !trans[p][ch])
            trans[p][ch] = z, p = link[p];
        if (!p) link[z] = 1;
        else{
            int x = trans[p][ch];
            if (maxlen[p] + 1 == maxlen[x]) link[z] = x;
            else{
                int y = ++Size;
                clr(y);
                maxlen[y] = maxlen[p] + 1;
                for (int i = 0; i < 26; ++i)
                    trans[y][i] = trans[x][i];
                while (p && trans[p][ch] == x)
                    trans[p][ch] = y, p = link[p];
                link[y] = link[x], link[z] = link[x] = y;
            }
        }
        return z;
    }
    int pre[Maxn],c[Maxn],vis[Maxn];
    void solve_init(){
        for(int i=0;i<=Size+1;i++)g[i].clear(),pre[i]=c[i]=vis[i]=0;;
        for(int i=2;i<=Size;i++)g[link[i]].push_back(i);
    }
    int in[Maxn],out[Maxn],num[Maxn],tim;
    void getdfn(int x,int fa){
        in[x]=++tim;
        num[tim]=x;
        for(int i=0;i<g[x].size();i++){
            if(g[x][i]==fa)continue;
            getdfn(g[x][i],x);
        }
        out[x]=tim;
        ask[x]={x,in[x],out[x]};
    }
    int ans[Maxn];
    void add(int x,int y){
        for(int i=x;i<=Size;i+=i&(-i))
            c[i]+=y;
    }
    int sum(int x){
        int ans=0;
        for(int i=x;i;i-=i&(-i))
            ans+=c[i];
        return ans;
    }
    int mx;
    char str[Maxn];
    void dfs(int x,int length){
        if(length==mx){
            if(vis[x]){
                str[length]='';
                puts(str);
            }
            return ;
        }
        for(int i=0;i<26;i++){
            if(trans[x][i]){
                str[length]='a'+i;
                dfs(trans[x][i],length+1);
            }
        }
    }   
    static bool cmp(Q x,Q y){return x.r < y.r;}
    void solve(){
        solve_init();
        tim=0;
        getdfn(1,-1);
        sort(ask+1,ask+1+Size,cmp);
        int now=1;
        for(int i=1;i<=Size;i++){
            for(int j=0;j<sz[num[i]].size();j++){
                if(pre[sz[num[i]][j]])
                    add(pre[sz[num[i]][j]],-1);
                add(i,1);
                pre[sz[num[i]][j]]=i;
            }
            while(now<=Size&&ask[now].r==i){
                ans[ask[now].id]=sum(i)-sum(ask[now].l-1);
                ++now;
            }
        }
        mx=0;
        for(int i=2;i<=Size;i++){
            if(ans[i]>n/2){
                mx=max(mx,maxlen[i]);
            }
        }
        for(int i=2;i<=Size;i++){
            if(ans[i]>n/2&&maxlen[i]==mx){
                vis[i]=1;
            }
        }
        if(mx==0)puts("?");
        else dfs(1,0);
        puts("");
    }
}sam;
char s[Maxn];
int main(){
    while(scanf("%d",&n)&&n){
        sam.init();
        for(int i=0;i<n;i++){
            scanf("%s",s);
            int last=1;
            for(int j=0;s[j];j++)
                last=sam.insert(s[j]-'a',last,i);
        }
        sam.solve();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Zeronera/p/13725692.html