算法介绍见:http://www.cnblogs.com/Sakits/p/8232402.html
广义SAM资料:https://www.cnblogs.com/phile/p/4511571.html
【例题】
参考http://www.cnblogs.com/Candyouth/p/5368750.html
因为$Parent$树上的叶子节点有可能变成一个父亲节点,所以可能某个叶子节点$r_i$不存在,比如$aa$,$r_i=1$的就不存在,它从一个叶子节点被更新成了父亲节点。
所以对于这题要统计子串个数,需要对每个$np$的贡献设为1,然后在$Parent$树上跑一遍,因为$np$初始都是叶子节点,即使他变成了父亲节点,还是有1的贡献,注意$nq$一开始就是父亲节点所以没有贡献。
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<algorithm> #define ll long long using namespace std; const int maxn=2000010, inf=1e9; struct sam{int len, fa, trans[26];}st[maxn]; struct poi{int too, pre;}e[maxn]; int n, tott, tot, now, root, cnt[maxn], size[maxn], last[maxn]; ll ans; char s[maxn]; inline void read(int &k) { int f=1; k=0; char c=getchar(); while(c<'0' || c>'9') c=='-'&&(f=-1), c=getchar(); while(c<='9' && c>='0') k=k*10+c-'0', c=getchar(); k*=f; } inline void add(int x, int y){e[++tot]=(poi){y, last[x]}; last[x]=tot;} inline void extend(int ch) { int np=++tott, p=now; size[np]=1; st[np].len=st[p].len+1; now=np; while(p && !st[p].trans[ch]) st[p].trans[ch]=np, p=st[p].fa; if(!p) st[np].fa=root; else { int q=st[p].trans[ch]; if(st[p].len+1==st[q].len) st[np].fa=q; else { int nq=++tott; st[nq]=st[q]; st[nq].len=st[p].len+1; st[np].fa=st[q].fa=nq; while(p && st[p].trans[ch]==q) st[p].trans[ch]=nq, p=st[p].fa; } } } void dfs(int x) { for(int i=last[x], too;i;i=e[i].pre) dfs(too=e[i].too), size[x]+=size[too]; if(size[x]!=1) ans=max(ans, 1ll*size[x]*st[x].len); } int main() { scanf("%s", s+1); n=strlen(s+1); now=tott=root=1; for(int i=1;i<=n;i++) extend(s[i]-'a'); for(int i=1;i<=tott;i++) add(st[i].fa, i); dfs(1); printf("%lld\n", ans); }