├── .gitignore ├── MergeTree.cpp ├── README.md ├── convex_hull.cc ├── crt.cpp ├── dijkstra.cc ├── fast_io.cc ├── fenwick.cc ├── fft.cpp ├── hopcroft_karp.cpp ├── karatsuba.cc ├── kmp.cc ├── lca.cc ├── manacher.cc ├── rotating_calipers.cc └── suffix_array.cc /.gitignore: -------------------------------------------------------------------------------- 1 | a.out 2 | -------------------------------------------------------------------------------- /MergeTree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | class MergeTree { 5 | public: 6 | int n, d; 7 | vector> vs; 8 | vector> ss; 9 | void Build(vector &a) { 10 | n = a.size(); 11 | d = sizeof(int) * 8 - __builtin_clz(n - 1) + 1; // log2-like; e.g., 7 -> 4, 8 -> 4, 9 -> 5 ... 12 | vs = vector>(d, vector(n)); 13 | ss = vector>(d, vector(n)); 14 | BuildNode(0, n - 1, 0, a); 15 | } 16 | void BuildNode(int s, int e, int d, vector &a) { 17 | if (s == e) { 18 | vs[d][s] = a[s]; 19 | return; 20 | } 21 | int m = (s + e) / 2; 22 | BuildNode(s, m, d + 1, a); 23 | BuildNode(m + 1, e, d + 1, a); 24 | int l = s, r = m + 1, i = s; 25 | while (l <= m || r <= e) { 26 | if (r > e || (l <= m && vs[d + 1][l] < vs[d + 1][r])) { 27 | vs[d][i] = vs[d + 1][l]; 28 | ss[d][i] = 0; 29 | ++i; ++l; 30 | } else { 31 | vs[d][i] = vs[d + 1][r]; 32 | ss[d][i] = 1; 33 | ++i; ++r; 34 | } 35 | } 36 | for (int i = s + 1; i <= e; ++i) { 37 | ss[d][i] += ss[d][i - 1]; 38 | } 39 | } 40 | // find largest index i s.t. l <= a[i] < r 41 | int Query1(int l, int r) { 42 | return QueryNode1(0, n - 1, 0, l, r); 43 | } 44 | int QueryNode1(int s, int e, int d, int l, int r) { 45 | if (s == e) { 46 | return s; 47 | } 48 | int li = lower_bound(vs[d].begin() + s, vs[d].begin() + e + 1, l) - vs[d].begin(); 49 | if (li == e + 1) return e + 1; 50 | int ri = lower_bound(vs[d].begin() + li, vs[d].begin() + e + 1, r) - vs[d].begin(); 51 | if (ri == li) return e + 1; 52 | int sw = ss[d][ri - 1] - (li == s ? 0 : ss[d][li - 1]); 53 | int m = (s + e) / 2; 54 | if (sw > 0) return QueryNode1(m + 1, e, d + 1, l, r); 55 | return QueryNode1(s, m, d + 1, l, r); 56 | } 57 | // count i s.t. i >= l and a[i] >= x 58 | int Query2(int l, int x) { 59 | return QueryNode2(0, n - 1, 0, l, x); 60 | } 61 | int QueryNode2(int s, int e, int d, int l, int x) { 62 | if (l <= s) { 63 | int xi = lower_bound(vs[d].begin() + s, vs[d].begin() + e + 1, x) - vs[d].begin(); 64 | return e + 1 - xi; 65 | } 66 | if (e < l) return 0; 67 | int m = (s + e) / 2, r = 0; 68 | r += QueryNode2(s, m, d + 1, l, x); 69 | r += QueryNode2(m + 1, e, d + 1, l, x); 70 | return r; 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # algorithm 2 | -------------------------------------------------------------------------------- /convex_hull.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | typedef long long ll; 7 | typedef pair Point; 8 | 9 | vector ConvexHull(vector &p) { 10 | if (p.size() <= 3) return p; 11 | swap(*p.begin(), *min_element(p.begin(), p.end())); 12 | auto ccw = [](Point const &a, Point const &b, Point const &c) { 13 | return a.first * b.second + b.first * c.second + c.first * a.second 14 | - b.first * a.second - c.first * b.second - a.first * c.second; 15 | }; 16 | sort(p.begin() + 1, p.end(), [&](Point const &a, Point const &b) { 17 | return ccw(*p.begin(), a, b) > 0; 18 | }); 19 | vector ch(p.begin(), p.begin() + 2); 20 | for (auto it = p.begin() + 2; it != p.end(); ++it) { 21 | while (ch.size() >= 2 && ccw(*(ch.end() - 2), *(ch.end() - 1), *it) <= 0) 22 | ch.pop_back(); 23 | ch.push_back(*it); 24 | } 25 | while (ch.size() >= 2 && ccw(*(ch.end() - 2), *(ch.end() - 1), *p.begin()) <= 0) 26 | ch.pop_back(); 27 | return ch; 28 | } 29 | 30 | int main() { 31 | int n; 32 | scanf("%d", &n); 33 | vector p; 34 | for (int i = 0; i < n; ++i) { 35 | int x, y; 36 | scanf("%d%d", &x, &y); 37 | p.push_back(Point(x, y)); 38 | } 39 | vector ch = ConvexHull(p); 40 | printf("%lu", ch.size()); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /crt.cpp: -------------------------------------------------------------------------------- 1 | /* Extended Euclidean Algorithm 2 | * find x, y s.t. ax+by=gcd(a,b) 3 | */ 4 | void eea(int a, int b, int &x, int &y) { 5 | int r[3] = {a, b}, s[3] = {1, 0}, t[3] = {0, 1}; 6 | while (r[1]) { 7 | int q = r[0] / r[1]; 8 | r[2] = r[0] - q * r[1]; 9 | s[2] = s[0] - q * s[1]; 10 | t[2] = t[0] - q * t[1];; 11 | r[0] = r[1]; r[1] = r[2]; 12 | s[0] = s[1]; s[1] = s[2]; 13 | t[0] = t[1]; t[1] = t[2]; 14 | } 15 | x = s[0]; y = t[0]; 16 | } 17 | 18 | /* Chinese Remainder Theorem 19 | * find x s.t. x = a[i] mod b[i] 20 | */ 21 | int crt(int *a, int *b, int n) { 22 | int B = 1; 23 | for (int i = 0; i < n; ++i) 24 | B *= b[i]; 25 | int x = 0; 26 | for (int i = 0; i < n; ++i) { 27 | int c, d; 28 | eea(b[i], B / b[i], c, d); 29 | x = (x + B / b[i] * d * a[i]) % B; 30 | } 31 | x = (x + B) % B; 32 | return x; 33 | } 34 | -------------------------------------------------------------------------------- /dijkstra.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | typedef pair pii; 8 | int const INF = 987654321; 9 | int main() { 10 | int n, m, a, b, c, s, t; 11 | scanf("%d%d", &n, &m); 12 | vector > g(n); 13 | for (int i = 0; i < m; ++i) { 14 | scanf("%d%d%d", &a, &b, &c); 15 | --a; --b; 16 | g[a].push_back(pii(b, c)); 17 | } 18 | scanf("%d%d", &s, &t); 19 | --s; --t; 20 | vector d(n, INF); 21 | priority_queue, greater > q; 22 | d[s] = 0; 23 | q.push(pii(0, s)); 24 | while (true) { 25 | int dist = q.top().first, here = q.top().second; 26 | if (here == t) break; 27 | q.pop(); 28 | if (d[here] == dist) { 29 | for (auto &p : g[here]) { 30 | int there = p.first, cost = p.second; 31 | if (d[there] > dist + cost) { 32 | d[there] = dist + cost; 33 | q.push(pii(d[there], there)); 34 | } 35 | } 36 | } 37 | } 38 | printf("%d", d[t]); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /fast_io.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | class FastIO { 4 | int fd, bufsz; 5 | char *buf, *cur, *end; 6 | public: 7 | FastIO(int _fd = 0, int _bufsz = 1 << 20) : fd(_fd), bufsz(_bufsz) { 8 | buf = cur = end = new char[bufsz]; 9 | } 10 | ~FastIO() { 11 | delete[] buf; 12 | } 13 | bool readbuf() { 14 | cur = buf; 15 | end = buf + bufsz; 16 | while (true) { 17 | size_t res = fread(cur, sizeof(char), end - cur, stdin); 18 | if (res == 0) break; 19 | cur += res; 20 | } 21 | end = cur; 22 | cur = buf; 23 | return buf != end; 24 | } 25 | int readint() { 26 | while (true) { 27 | if (cur == end) readbuf(); 28 | if (isdigit(*cur) || *cur == '-') break; 29 | ++cur; 30 | } 31 | bool sign = true; 32 | if (*cur == '-') { 33 | sign = false; 34 | ++cur; 35 | } 36 | int ret = 0; 37 | while (true) { 38 | if (cur == end && !readbuf()) break; 39 | if (!isdigit(*cur)) break; 40 | ret = ret * 10 + (*cur - '0'); 41 | ++cur; 42 | } 43 | return sign ? ret : -ret; 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /fenwick.cc: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /* 5 | * 1-based index 6 | */ 7 | template 8 | class Fenwick { 9 | int n; 10 | vector a; 11 | public: 12 | Fenwick(int _n) : n(_n), a(_n + 1) {} 13 | void update(int p, T x) { for (; p <= n; p += p & (-p)) a[p] += x; } 14 | T query(int p) { T s = 0; for (; p > 0; p -= p & (-p)) s += a[p]; return s; } 15 | }; 16 | 17 | /* 18 | * Point update : a[p] += x 19 | * Range query : a[s] + ... + a[e] 20 | */ 21 | void update(int p, int x) { 22 | fw.update(p, x); 23 | } 24 | int query(int s, int e) { 25 | return fw.query(e) - fw.query(s - 1); 26 | } 27 | 28 | /* 29 | * Range update : a[s] += x, ..., a[e] += x 30 | * Point query : a[p] 31 | */ 32 | void update(int s, int e, int x) { 33 | fw.update(s, x); 34 | fw.update(e + 1, -x); 35 | } 36 | int query(int p) { 37 | return fw.query(p); 38 | } 39 | 40 | /* 41 | * Range update : a[s] += x, ..., a[e] += x 42 | * Range query : a[s] + ... + a[e] 43 | */ 44 | void update(int s, int e, int x) { 45 | fw0.update(s, x); 46 | fw0.update(e + 1, -x); 47 | fw1.update(s, x * (s - 1)); 48 | fw1.update(e + 1, -x * e); 49 | } 50 | int query(int p) { 51 | return fw0.query(p) * p - fw1.query(p); 52 | } 53 | -------------------------------------------------------------------------------- /fft.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | typedef complex cd; 8 | 9 | int const NMAX = 1 << 9; 10 | double const PI2 = atan(1.0) * 8; 11 | cd a[NMAX], b[NMAX]; 12 | 13 | // fft(src, num, stride, dst, nth root of unity) 14 | void fft(cd *a, int n, int s, cd *b, cd unit) { 15 | if (n == 1) { 16 | *b = *a; 17 | return; 18 | } 19 | int nh = n / 2; 20 | fft(a , nh, s * 2, b , unit * unit); 21 | fft(a + s, nh, s * 2, b + nh, unit * unit); 22 | cd coef = 1; 23 | for (int i = 0; i < nh; ++i) { 24 | cd ofs = coef * b[i + nh]; 25 | b[i + nh] = b[i] - ofs; 26 | b[i] = b[i] + ofs; 27 | coef *= unit; 28 | } 29 | } 30 | 31 | int main() { 32 | // should be power of 2 33 | int n; 34 | cin >> n; 35 | for (int i = 0; i < n; ++i) { 36 | int t; 37 | cin >> t; 38 | a[i] = cd(t, 0); 39 | } 40 | 41 | // fft 42 | fft(a, n, 1, b, polar(1.0, -PI2 / n)); 43 | for (int i = 0; i < n; ++i) 44 | cout << b[i] << ' '; 45 | cout << endl; 46 | 47 | // inverse fft 48 | fft(b, n, 1, a, polar(1.0, PI2 / n)); 49 | for (int i = 0; i < n; ++i) 50 | a[i] /= n; 51 | for (int i = 0; i < n; ++i) 52 | cout << a[i] << ' '; 53 | cout << endl; 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /hopcroft_karp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | struct HK { 9 | int n, m, dd; 10 | vector > g; 11 | vector xy, yx, d; 12 | 13 | HK(int n, int m) : n(n), m(m), g(n), xy(n), yx(m), d(n) {} 14 | 15 | bool bfs() { 16 | queue q; 17 | for(int x = 0; x < n; ++x) { 18 | if(xy[x] == -1) { 19 | d[x] = 0; 20 | q.push(x); 21 | } else { 22 | d[x] = -1; 23 | } 24 | } 25 | while(!q.empty()) { 26 | int x = q.front(); q.pop(); 27 | for(int y : g[x]) { 28 | if(yx[y] == -1) { 29 | dd = d[x]; 30 | return true; 31 | } 32 | if(d[yx[y]] == -1) { 33 | d[yx[y]] = d[x] + 1; 34 | q.push(yx[y]); 35 | } 36 | } 37 | } 38 | return false; 39 | } 40 | 41 | bool dfs(int x) { 42 | for(int y : g[x]) { 43 | if((yx[y] == -1 && dd == d[x]) || (d[yx[y]] == d[x] + 1 && dfs(yx[y]))) { 44 | xy[x] = y; 45 | yx[y] = x; 46 | return true; 47 | } 48 | } 49 | d[x] = -1; 50 | return false; 51 | } 52 | 53 | int match() { 54 | fill(xy.begin(), xy.end(), -1); 55 | fill(yx.begin(), yx.end(), -1); 56 | int matched = 0; 57 | while(bfs()) 58 | for(int x = 0; x < n; ++x) 59 | if(xy[x] == -1 && dfs(x)) 60 | ++matched; 61 | return matched; 62 | } 63 | }; 64 | 65 | int main() { 66 | int n, m; 67 | scanf("%d%d", &n, &m); 68 | HK hk(n, m); 69 | int e; 70 | scanf("%d", &e); 71 | for(int i = 0; i < e; ++i) { 72 | int x, y; 73 | scanf("%d%d", &x, &y); 74 | hk.g[x].push_back(y); 75 | } 76 | printf("%d", hk.match()); 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /karatsuba.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | template 5 | class Karatsuba { 6 | typedef typename vector::iterator vTi; 7 | int cut; 8 | void convolve_naive(vTi a, vTi b, vTi c, int n) { 9 | int n2 = n * 2; 10 | for (int i = 0; i < n2; ++i) 11 | c[i] = 0; 12 | for (int i = 0; i < n; ++i) 13 | for (int j = 0; j < n; ++j) 14 | c[i + j] += a[i] * b[j]; 15 | } 16 | /* 17 | * v----d----v v-dh-v 18 | * ------------------------------------------------------------- 19 | * | al * bl | ah * bh | as * bs | | | as | bs | 20 | * ------------------------------------------------------------- 21 | * ^x0 ^xh ^x1 ^x2 22 | */ 23 | void karatsuba(vTi a, vTi b, vTi c, int n) { 24 | if(n <= cut) { 25 | convolve_naive(a, b, c, n); 26 | return; 27 | } 28 | int nh = n / 2; 29 | vTi al = a, ah = a + nh, as = c + nh * 10; 30 | vTi bl = b, bh = b + nh, bs = c + nh * 11; 31 | vTi x0 = c, x1 = c + n, x2 = c + n * 2, xh = c + nh; 32 | for (int i = 0; i < nh; ++i) { 33 | as[i] = al[i] + ah[i]; 34 | bs[i] = bl[i] + bh[i]; 35 | } 36 | karatsuba(al, bl, x0, nh); 37 | karatsuba(ah, bh, x1, nh); 38 | karatsuba(as, bs, x2, nh); 39 | for (int i = 0; i < n; ++i) x2[i] -= x0[i] + x1[i]; 40 | for (int i = 0; i < n; ++i) xh[i] += x2[i]; 41 | } 42 | public: 43 | Karatsuba(int _cut = 1 << 5) : cut(_cut) {} 44 | vector convolve(vector &_a, vector &_b) { 45 | vector a = _a, b = _b, c; 46 | int sz = max(a.size(), b.size()), sz2; 47 | for (sz2 = 1; sz2 < sz; sz2 *= 2); 48 | a.resize(sz2); b.resize(sz2); c.resize(sz2 * 6); 49 | karatsuba(a.begin(), b.begin(), c.begin(), sz2); 50 | c.resize(_a.size() + _b.size() - 1); 51 | return c; 52 | } 53 | }; 54 | 55 | #include 56 | int main() { 57 | int n; 58 | scanf("%d", &n); 59 | vector a(n), b(n); 60 | for (int i = 0; i < n; ++i) scanf("%d", &a[i]); 61 | for (int i = 0; i < n; ++i) scanf("%d", &b[i]); 62 | Karatsuba kt; 63 | vector c = kt.convolve(a, b); 64 | for (int x : c) printf("%d ", x); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /kmp.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | int const NMAX = 1000001; 5 | char a[NMAX], b[NMAX]; 6 | int t[NMAX]; 7 | 8 | int main() { 9 | gets(a); gets(b); 10 | 11 | int pos = 2, cnd = 0; 12 | while (b[pos - 1]) { 13 | if (b[pos - 1] == b[cnd]) 14 | t[pos++] = ++cnd; 15 | else if (cnd) 16 | cnd = t[cnd]; 17 | else 18 | t[pos++] = 0; 19 | } 20 | 21 | int m = 0, i = 0; 22 | vector ans; 23 | while (a[m + i]) { 24 | if (a[m + i] == b[i]) { 25 | if (!b[++i]) ans.push_back(m); 26 | } else if (i) { 27 | m += i - t[i]; 28 | i = t[i]; 29 | } else { 30 | ++m; 31 | } 32 | } 33 | 34 | printf("%lu\n", ans.size()); 35 | for (int i : ans) 36 | printf("%d ", i + 1); 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /lca.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | typedef pair pii; 7 | 8 | class LCA { 9 | // b = segment tree base 10 | int n, b; 11 | // t[b + i] = (level, #) of ith visited node in euler tour 12 | vector t; 13 | // r[i] = first visit of node i 14 | vector r; 15 | // euler tour (graph, current, parent, height, visit index) 16 | int et(vector> &g, int x, int p = -1, int h = 0, int c = 0) { 17 | r[x] = c; 18 | t[b + c++] = pii(h, x); 19 | for (int y : g[x]) { 20 | if (y != p) { 21 | c = et(g, y, x, h + 1, c); 22 | t[b + c++] = pii(h, x); 23 | } 24 | } 25 | return c; 26 | } 27 | // query on segment tree 28 | int tq(int x, int y) { 29 | x += b; y += b; 30 | pii m(t[x]); 31 | while (x < y) { 32 | if (x % 2 == 1) m = min(m, t[x++]); 33 | if (y % 2 == 0) m = min(m, t[y--]); 34 | x /= 2; y /= 2; 35 | } 36 | if (x == y) m = min(m, t[x]); 37 | return m.second; 38 | } 39 | public: 40 | // initialize with graph 41 | void init(vector> &g) { 42 | n = g.size(); 43 | // euler tour visits 2n-1 nodes 44 | for (b = 1; b < 2 * n - 1; b *= 2); 45 | t = vector(b * 2); 46 | r = vector(n); 47 | et(g, 0); 48 | // since it's min segment tree, INF padding is needed 49 | for (int i = b + 2 * n - 1; i < b * 2; ++i) { 50 | t[i] = pii(n, 0); 51 | } 52 | for (int i = b - 1; i > 0; --i) { 53 | t[i] = min(t[i * 2], t[i * 2 + 1]); 54 | } 55 | } 56 | // query lca of x and y 57 | int q(int x, int y) { 58 | x = r[x]; y = r[y]; 59 | return tq(min(x, y), max(x, y)); 60 | } 61 | }; 62 | 63 | int main() { 64 | int n; 65 | scanf("%d", &n); 66 | vector> g(n); 67 | for (int i = 1; i < n; ++i) { 68 | int a, b; 69 | scanf("%d%d", &a, &b); 70 | --a; --b; 71 | g[a].push_back(b); 72 | g[b].push_back(a); 73 | } 74 | 75 | LCA lca; 76 | lca.init(g); 77 | 78 | int m; 79 | scanf("%d", &m); 80 | for (int i = 0; i < m; ++i) { 81 | int c, d; 82 | scanf("%d%d", &c, &d); 83 | --c; --d; 84 | printf("%d\n", lca.q(c, d) + 1); 85 | } 86 | 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /manacher.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | int a[4000], d[4000]; 5 | int main() { 6 | int n; 7 | scanf("%d", &n); 8 | n *= 2; 9 | for (int i = 0; i < n; i += 2) 10 | scanf("%d", &a[i]); 11 | int r = -1, p; 12 | for (int i = 0; i < n; ++i) { 13 | if (i <= r) 14 | d[i] = min(r - i, d[p * 2 - i]); 15 | while (i - d[i] > 0 && a[i - d[i] - 1] == a[i + d[i] + 1]) 16 | ++d[i]; 17 | if (r < i + d[i]) { 18 | r = i + d[i]; 19 | p = i; 20 | } 21 | } 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /rotating_calipers.cc: -------------------------------------------------------------------------------- 1 | void RotatingCalipers(vector &p) { 2 | int n = p.size(); 3 | int p0 = min_element(p.begin(), p.end()) - p.begin(), np0 = (p0 + 1) % n; 4 | int p1 = max_element(p.begin(), p.end()) - p.begin(), np1 = (p1 + 1) % n; 5 | for (int i = 0; i < n * 2; ++i) { 6 | ll det = (p[np1].second - p[p1].second) * (p[np0].first - p[p0].first) 7 | - (p[np0].second - p[p0].second) * (p[np1].first - p[p1].first); 8 | if (det >= 0) { 9 | p1 = np1; 10 | np1 = (np1 + 1) % n; 11 | } 12 | if (det <= 0) { 13 | p0 = np0; 14 | np0 = (np0 + 1) % n; 15 | } 16 | // p[p0] and p[p1] are antipodal, so do sth here 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /suffix_array.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | class SuffixArray { 9 | public: 10 | class Comparator { 11 | char *s; 12 | public: 13 | Comparator(char *_s) : s(_s) {} 14 | bool operator () (int x, int y) { return s[x] < s[y]; } 15 | }; 16 | 17 | vector sa; 18 | vector lcp; 19 | 20 | SuffixArray(int n, char *s) { 21 | vector g(n + 1); // group 22 | vector g2(n); // auxiliary 23 | vector gpos(n); // position for bucket sort 24 | sa = vector(n); // suffix array 25 | vector sa2(n); // auxiliary 26 | lcp = vector(n); // lcp array 27 | 28 | // init sa, g, and gpos 29 | for (int i = 0; i < n; ++i) sa[i] = i; 30 | sort(sa.begin(), sa.end(), Comparator(s)); 31 | int gn = 0; 32 | g[sa[0]] = gn; gpos[gn] = 0; 33 | for (int i = 1; i < n; ++i) { 34 | if (s[sa[i - 1]] != s[sa[i]]) 35 | gpos[++gn] = i; 36 | g[sa[i]] = gn; 37 | } 38 | // this prevents index go beyond n, during comparison 39 | g[n] = -1; 40 | 41 | // condition g[sa[n - 1]] < n - 1 greatly reduces running time 42 | for (int d = 1; g[sa[n - 1]] < n - 1; d *= 2) { 43 | // characters beyond n - d have nothing to append, so just put it 44 | for (int i = n - d; i < n; ++i) 45 | sa2[gpos[g[i]]++] = i; 46 | // otherwise, append [sa[i], sa[i] + d) to [sa[i] - d, sa[i]) 47 | for (int i = 0; i < n; ++i) 48 | if (sa[i] >= d) 49 | sa2[gpos[g[sa[i] - d]]++] = sa[i] - d; 50 | 51 | // copying sa2 to sa, update new group number on g2, and init gpos 52 | gn = 0; 53 | sa[0] = sa2[0]; g2[sa[0]] = gn; gpos[gn] = 0; 54 | for (int i = 1; i < n; ++i) { 55 | if (g[sa2[i - 1]] != g[sa2[i]] || g[sa2[i - 1] + d] != g[sa2[i] + d]) 56 | gpos[++gn] = i; 57 | sa[i] = sa2[i]; 58 | g2[sa[i]] = gn; 59 | } 60 | // copying g2 to g 61 | for (int i = 0; i < n; ++i) 62 | g[i] = g2[i]; 63 | } 64 | 65 | // lcp construct 66 | for (int i = 0, k = 0; i < n; ++i) { 67 | if (g[i] > 0) { 68 | for (int j = sa[g[i] - 1]; s[i + k] == s[j + k]; ++k); 69 | lcp[g[i]] = k; 70 | // next substring will have at least k - 1 length CP 71 | // so don't need to reset, just decrease by 1 72 | if (k) --k; 73 | } 74 | } 75 | } 76 | }; 77 | 78 | char s[1001]; 79 | int main() { 80 | scanf("%s", s); 81 | int n = strlen(s); 82 | SuffixArray sa(n, s); 83 | for (int i = 0; i < n; ++i) 84 | printf("%s\n", s + sa.sa[i]); 85 | return 0; 86 | } 87 | --------------------------------------------------------------------------------