SAM模板


SAM:

//计算本质不同的串个数
//答案为sum(len[x]-len[fa])

#include
using namespace std;
#define ll long long
const int maxm=2e6+5;
char s[maxm];
struct SAM{
    int ch[maxm][26];
    int fa[maxm],l[maxm];//l[]是等价类的最长字符串长度len
    int last=1,tot=1;//tot是节点数量
    void add(int c){//需要传入s[i]-'a',而不是s[i]
        int p=last,np=++tot;last=np;l[np]=l[p]+1;
        for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
        if(!p)fa[np]=1;
        else{
            int q=ch[p][c];
            if(l[p]+1==l[q])fa[np]=q;
            else{
                int nq=++tot;l[nq]=l[p]+1;
                memcpy(ch[nq],ch[q],sizeof ch[q]);
                fa[nq]=fa[q];fa[q]=fa[np]=nq;
                for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq;
            }
        }
    }
    void init(){
        for(int i=1;i<=tot;i++){
            memset(ch[i],0,sizeof ch[i]);
            fa[i]=l[i]=0;
        }
        last=tot=1;
    }
    void solve(){
        ll ans=0;
        for(int i=2;i<=tot;i++){
            ans+=l[i]-l[fa[i]];
        }
        cout<<ans<<endl;
    }
}T;
signed main(){
    int TT;scanf("%d",&TT);
    while(TT--){
        scanf("%s",s+1);
        int q;scanf("%d",&q);
        while(q--){
            int l,r;scanf("%d%d",&l,&r);
            T.init();
            for(int i=l;i<=r;i++){
                T.add(s[i]-'a');
            }
            T.solve();
        }
    }
    return 0;
}

重要结论:

1.每个状态x的maxlen和minlen的关系
maxlen[fa]=minlen[x]-1
2.1得来的推论:
本质不同的串个数=sum(len[x]-len[fa])

你可能感兴趣的:(SAM模板)