一点疑问:
当创建nq节点时,要不要把nq的cnt标记赋值为1?
讲道理nq节点也是代表一个子串啊,不过网上的模板都没赋值。
2017.9.18 update:
把memset部分重写,改成用节点用到时再初始化,初始化所有节点可能被卡。
fa,len,cnt数组其实不用清空,因为用时都赋值了。
1 struct SAM 2 { 3 static const int MAXN = 300001<<1;//大小为字符串长度两倍 4 static const int LetterSize = 26; 5 6 int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN]; 7 int sum[MAXN], tp[MAXN], cnt[MAXN]; //sum,tp用于拓扑排序,tp为排序后的数组 8 9 void init( void) 10 { 11 last = tot = 1; 12 len[1] = 0; 13 memset( ch[1], 0, sizeof ch[1]); 14 } 15 16 void add( int x) 17 { 18 int p = last, np = last = ++tot; 19 len[np] = len[p] + 1, cnt[last] = 1; 20 memset( ch[np], 0, sizeof ch[np]); 21 while( p && !ch[p][x]) ch[p][x] = np, p = fa[p]; 22 if( p == 0) 23 fa[np] = 1; 24 else 25 { 26 int q = ch[p][x]; 27 if( len[q] == len[p] + 1) 28 fa[np] = q; 29 else 30 { 31 int nq = ++tot; 32 memcpy( ch[nq], ch[q], sizeof ch[q]); 33 len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq; 34 while( p && ch[p][x] == q) ch[p][x] = nq, p = fa[p]; 35 } 36 } 37 } 38 39 void toposort( void) 40 { 41 for(int i = 1; i <= len[last]; i++) sum[i] = 0; 42 for(int i = 1; i <= tot; i++) sum[len[i]]++; 43 for(int i = 1; i <= len[last]; i++) sum[i] += sum[i-1]; 44 for(int i = 1; i <= tot; i++) tp[sum[len[i]]--] = i; 45 for(int i = tot; i; i--) cnt[fa[tp[i]]] += cnt[tp[i]]; 46 } 47 } sam;