template struct SAM { vector fa, len; vector cloned; vector cnt; vector> ch; int last; int tot; int create(int _fa, int _len, bool _cloned, array&& _ch) { fa.emplace_back(_fa); len.emplace_back(_len); cloned.emplace_back(_cloned); ch.emplace_back(_ch); return tot++; } SAM(void) : fa(2), len(2), cloned(2), ch(2), last(1), tot(2) {} void push_back(size_t c) { int p = last; int nw = create(0, len[p] + 1, false, {}); while (p != 0 and ch[p][c] == 0) { ch[p][c] = nw; p = fa[p]; } if (p == 0) { fa[nw] = 1; } else { int q = ch[p][c]; if (len[q] == len[p] + 1) { fa[nw] = q; } else { int nq = create(fa[q], len[p] + 1, true, array(ch[q])); fa[nw] = fa[q] = nq; while (p != 0 and ch[p][c] == q) { ch[p][c] = nq; p = fa[p]; } } } last = nw; } template optional find(const basic_string& seq) { int p = 1; for (auto&& c : seq) { if (ch[p][c] == 0) { return nullopt; } p = ch[p][c]; } return p; } // Fill `cnt` with the number of occurrences of each substring. void populate(void) { cnt.assign(tot, 0); vector idx(tot); iota(idx.begin(), idx.end(), 0); sort_by_key(idx.begin(), idx.end(), expr(len[i], auto&& i), greater()); for (auto&& v : idx) { if (v > 1 and not cloned[v]) { cnt[v] += 1; } cnt[fa[v]] += cnt[v]; } } };