const int N = 1e5, VN = 2 * N; char s[N + 1]; map t[VN]; int l[VN], r[VN], p[VN]; // ребро p[v] -> v это отрезок [l[v], r[v]) исходной строки int root = 1; int cc, n, suf[VN], vn = 2, v = root, pos = 0; // идём по ребру из p[v] в v, сейчас стоим в pos int main() { readWord(s); forn(i, 127) t[0][i] = 1; // 0 = фиктивная, 1 = корень l[1] = -1, r[1] = 0; v = root, pos = 0; for (n = 0; s[n]; n++) { char c = s[n]; auto new_leaf = [&]( int v ) { p[vn] = v, l[vn] = n, r[vn] = N, t[v][c] = vn++; }; go:; if (r[v] == pos) { // дошёл до конца ребра if (!t[v].count(c)) { new_leaf(v), v = suf[v], pos = r[v]; goto go; } v = t[v][c], pos = l[v] + 1; } else if (c == s[pos]) { pos++; } else { int x = vn++; l[x] = l[v], r[x] = pos, l[v] = pos; p[x] = p[v], p[v] = x; t[p[x]][s[l[x]]] = x; // t[p[v]][s[l[v]]] = v; t[x][s[pos]] = v; new_leaf(x); v = suf[p[x]], pos = l[x]; while (pos < r[x]) v = t[v][s[pos]], pos += r[v] - l[v]; suf[x] = (pos == r[x] ? v : vn); pos = r[v] - (pos - r[x]); goto go; } } printf("%d\n", vn - 1); // go(1); } // void go( int v ) { // int no = cc++; // for (auto p : t[v]) { // v = p.second; // printf("%d %d %d\n", no, l[v], min(n, r[v])); // go(v); // } // }