要省选啦!码码板子……
const int N = 200010; char st[N]; int rk[N], sa[N], nr[N], ns[N], tab[N], hi[N]; void calc(int n) { for (int i = 0; i <= 26; ++ i) tab[i] = 0; for (int i = 1; i <= n; ++ i) tab[st[i] - 'a' + 1] = 1; for (int i = 1; i <= 26; ++ i) tab[i] += tab[i - 1]; for (int i = 1; i <= n; ++ i) rk[i] = tab[st[i] - 'a' + 1]; for (int p = 2; (p >> 1) <= n; p <<= 1) { for (int i = 0; i <= n; ++ i) tab[i] = 0; for (int i = 1; i <= n; ++ i) tab[rk[i + (p >> 1)]] ++; for (int i = 1; i <= n; ++ i) tab[i] += tab[i - 1]; for (int i = n; i >= 1; -- i) ns[tab[rk[i + (p >> 1)]] --] = i; for (int i = 0; i <= n; ++ i) tab[i] = 0; for (int i = 1; i <= n; ++ i) tab[rk[i]] ++; for (int i = 1; i <= n; ++ i) tab[i] += tab[i - 1]; for (int i = n; i >= 1; -- i) sa[tab[rk[ns[i]]] --] = ns[i]; nr[sa[1]] = 1; for (int i = 2; i <= n; ++ i) if (rk[sa[i]] == rk[sa[i - 1]] && rk[sa[i] + (p >> 1)] == rk[sa[i - 1] + (p >> 1)]) nr[sa[i]] = nr[sa[i - 1]]; else nr[sa[i]] = nr[sa[i - 1]] + 1; for (int i = 1; i <= n; ++ i) rk[i] = nr[i]; if (rk[sa[n]] == n) break; } for (int i = 1; i <= n; ++ i) if (rk[i] != 1) { hi[rk[i]] = max(hi[rk[i - 1]] - 1, 0); while (st[i + hi[rk[i]]] == st[sa[rk[i] - 1] + hi[rk[i]]]) hi[rk[i]] ++; } }
这个SA奇满无比…… 但至少能用?
const int N = 200000; int nxt[N][30], par[N], len[N], tot; int append(int p, int c) { if (nxt[p][c] && len[nxt[p][c]] == len[p] + 1) return nxt[p][c]; int np = ++ tot, f = nxt[p][c]; len[np] = len[p] + 1; while (p && !nxt[p][c]) nxt[p][c] = np, p = par[p]; if (!p) par[np] = 1; else { int q = nxt[p][c]; if (len[q] == len[p] + 1) par[np] = q; else { int nq = f ? np : ++ tot; len[nq] = len[p] + 1; memcpy(nxt[nq], nxt[q], sizeof(nxt[q])); par[nq] = par[q]; par[q] = nq; if (!f) par[np] = nq; while (p && nxt[p][c] == q) nxt[p][c] = nq, p = par[p]; } } return np; }
这个SAM应该是真的SAM!建在trie树上不会有无用节点~
const int N = 200000; char st[N]; int n, len[N]; void manacher(int n) { int md = 0, mx = 0; for (int i = 1; i <= n; ++ i) { if (mx >= i) len[i] = min(mx - i, len[md * 2 - i]); while (st[i + len[i]] == st[i - len[i]]) len[i] ++; if (i + len[i] > mx) mx = i + len[i], md = i; } }
马拉车~
const int N = 200000; char st[N]; int nxt[N][30], par[N], len[N], n, tot, p; int append(int p, int c, int i) { while (st[i] != st[i - len[p] - 1]) p = par[p]; if (!nxt[p][c]) { int np = nxt[p][c] = ++ tot; len[np] = len[p] + 2; int q = par[p]; while (q && !nxt[q][c]) q = par[q]; if (!q) par[np] = 2; else par[np] = nxt[q][c]; } return nxt[p][c]; }
PAM好像非常短的样子呢
const int N = 200000; char st[N]; int n; int calc(int n) { int i = 1, j = 2, k = 0; for (; i <= n && j <= n && k < n; ) { int si = st[i + k > n ? i + k - n : i + k], sj = st[j + k > n ? j + k - n : j + k]; if (si == sj) k ++; else { if (si < sj) j += k + 1; else i += k + 1; k = 0; if (i == j) j ++; } } return min(i, j); }
以前从来没有写过最小表示法QAQ
好像都是字符串算法,补一些其他的东西吧
struct treap { treap *left, *right; int siz, val; treap () { left = right = NULL; siz = val = 0; } treap *update() { this->siz = 1; if (this->left != NULL) this->siz += this->left->siz; if (this->right != NULL) this->siz += this->right->siz; return this; } treap *push_down() { return this; } treap *append(treap *p) { this->siz += p->siz; return this; } }; treap *join(treap *t1, treap *t2) { if (t1 == NULL) return t2; if (t2 == NULL) return t1; if (rand() % (t1->siz + t2->siz) < t1->siz) { t1->push_down(); t1->right = join(t1->right, t2); return t1->update(); } else { t2->push_down(); t2->left = join(t1, t2->left); return t2->update(); } } auto split(treap *t, treap *p) { if (t == NULL) return make_pair((treap*)NULL, (treap*)NULL); t->push_down(); if (p->val < t->val) { auto f = split(t->left, p); t->left = f.second; return make_pair(f.first, t->update()); } else { auto f = split(t->right, p); t->right = f.first; return make_pair(t->update(), f.second); } } treap *insert(treap *t, treap *p) { if (t == NULL || rand() % (t->siz + 1) == 0) { auto f = split(t, p); p->left = f.first; p->right = f.second; return p->update(); } else { t->push_down(); if (p->val < t->val) t->left = insert(t->left, p); else t->right = insert(t->right, p); return t->append(p); } } treap *erase(treap *t, treap *p) { if (t == NULL) return NULL; t->push_down(); if (t->val == p->val) return join(t->left, t->right); else if (p->val < t->val) t->left = erase(t->left, p); else t->right = erase(t->right, p); return t->update(); } treap *merge(treap *t1, treap *t2) { if (t1 == NULL) return t2; if (t2 == NULL) return t1; if (rand() % (t1->siz + t2->siz) < t2->siz) swap(t1, t2); auto f = split(t2, t1); t1->push_down(); t1->left = merge(t1->left, f.first); t1->right = merge(t1->right, f.second); return t1->update(); }
一棵非常优秀的二叉排序树,可以在上面套其他数据结构!(不过二叉排序树上怎么套东西?