1. 程式人生 > >【文文殿下】[51nod1469] 淋漓盡致子串

【文文殿下】[51nod1469] 淋漓盡致子串

SAM的經典應用

一個狀態的SIze==1絕對不合法。

一個狀態在parent樹上有一個Size>1的後繼絕對不合法(前面可以再補字元)

一個狀態可以轉移到Size>1的節點絕對不合法,因為可以在後面補字元。

#include<cstdio>
#include<cstring>
#include<map>
typedef long long ll;
const int maxn = 2e5+20;
int par[maxn],mx[maxn],tr[maxn][26],Right[maxn],c[maxn],id[maxn];
char A[maxn>>1];
int tot=0;
int cnt = 1,last = 1;
ll ans = 0;
void extend(int x) {
    int np = ++cnt,p = last;
    Right[np]=1;
    mx[np]=mx[p]+1;
    last=np;
    while(p&&!tr[p][x]) tr[p][x]=np,p=par[p];
    if(!p) par[np]=1;
    else {
        int q = tr[p][x];
        if(mx[q]==mx[p]+1) {
            par[np]=q;
        }
        else {
            int nq = ++cnt;
            mx[nq]=mx[p]+1;
            memcpy(tr[nq],tr[q],sizeof tr[nq]);
            par[nq]=par[q];
            par[q]=par[np]=nq;
            while(p&&tr[p][x]==q) tr[p][x]=nq,p=par[p];
        }
    }
    return;
}
int n,k,t;
inline void topsort() {
    for(int i = 1;i<=cnt;++i) ++c[mx[i]];
    for(int i = 1;i<=n;++i) c[i]+=c[i-1];
    for(int i = 1;i<=cnt;++i) id[c[mx[i]]--]=i;
    for(int i = cnt;i;--i) Right[par[id[i]]]+=Right[id[i]];
    return;
}
bool vis[maxn];
int main() {
    scanf("%s",A+1);
    n = strlen(A+1);
    for(int i = 1;i<=n;++i) extend(A[i]-'a');
    topsort();Right[0]=0;
    for(int i =cnt;i;--i) {
        if(Right[id[i]]>1||vis[id[i]]) vis[par[id[i]]]=1;
    }
    for(int i = 1;i<=cnt;++i) if(Right[i]<=1) vis[i]=1;
    for(int i = 1;i<=cnt;++i) for(int j = 0;j<26;++j) if(Right[tr[i][j]]>1) vis[i]=1;
    for(int i = 2;i<=cnt;++i) if(!vis[i]) ++ans;
    printf("%lld\n",ans);
    return 0;
}