【板子】后缀自动机(SAM)

//lg 3804
//Copyright yeyou26

#include<bits/stdc++.h>
using namespace std;

//注意:这道题不是纯纯的后缀自动机,main函数有一点额外处理
#define ll long long
#define N (int(2e6+6))

int fa[N],ch[N][28],len[N],cnt[N],idx=1,np=1;
ll ans;
string s;
vector<int> e[N];

void Addsam(int c);
ll calculate();
void dfs(int u);

int main()
{
    freopen("working.in","r",stdin);
    freopen("working.out","w",stdout);
    cin>>s;
    for(int i=0;s[i];i++)
    {
        Addsam(s[i]&31);
    }
    for(int i=2;i<=idx;i++)
    {
        e[fa[i]].push_back(i);
    }
    dfs(1);
    cout<<ans;
    return 0;
}

//Function Implementation

void dfs(int u)
{
    for(int v : e[u])
    {
        dfs(v);
        cnt[u]+=cnt[v];
    }
    if(cnt[u]>1) ans=max(ans,(ll)cnt[u]*len[u]);
}

void Addsam(int c)
{
    //p回跳指针 np新节点 q链接点 nq分裂链接点
    int p=np,np=++idx;
    len[np]=len[p]+1;
    cnt[np]=1;
    for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
    //case 1 找不到任何出现过(新串后缀)
    if(p==0) fa[np]=1;
    else 
    {   
        int q=ch[p][c];
        //case 2 链接点合法,直接连
        if(len[q]==len[p]+1) fa[np]=q;
        else 
        {
            //case 3 链接点不合法,裂开为nq和q,q负责长度大于len(p)+1的串,nq负责长度小于等于len(p)+1的串
            int nq=++idx;
            len[nq]=len[p]+1;
            fa[nq]=fa[q];fa[q]=nq;fa[np]=nq;
            //指向q的转移边指向nq
            for(;p && ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
            //从q出发的转移边丢给nq一份
            memcpy(ch[nq],ch[q],sizeof(ch[q]));  
        }
    }
}
posted @ 2024-01-26 20:58  yeyou26  阅读(7)  评论(0编辑  收藏  举报