AC自动机
点击查看代码
int ed[N];
const char CH = '0';
const int H = 10;
struct AC {
struct Node {
int son[H]; // 子结点
int fail; // fail 指针
int cnt;
long long sum;
void init() { // 结点初始化
memset(son, 0, sizeof(son));
fail = cnt = 0;
sum = 0;
}
};
vector<Node>tr;
int tot; // 结点总数
void init() {
tot = 0;
tr.clear();
tr.emplace_back();
tr[0].init();
}
void insert(string &s) {
int u = 0;
int L = s.length();
for (int i = 0; i < L; i++) {
if (!tr[u].son[s[i] - CH]) {
tr[u].son[s[i] - CH] = ++tot;
tr.emplace_back();
tr[tr[u].son[s[i] - CH]].init();
}
u = tr[u].son[s[i] - CH]; // 从下一个结点继续
}
ed[u] = 1;
tr[u].cnt++;
}
void build() {
queue<int> q;
for (int i = 0; i < H; i++)
if (tr[0].son[i]) {
tr[tr[0].son[i]].sum = tr[tr[0].son[i]].cnt;
q.push(tr[0].son[i]);
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0; i < H; i++) {
if (tr[u].son[i]) { // 存在对应子结点
tr[tr[u].son[i]].fail = tr[tr[u].fail].son[i]; // 只用跳一次 fail 指针
ed[tr[u].son[i]] |= ed[tr[tr[u].son[i]].fail];
tr[tr[u].son[i]].sum = tr[tr[u].son[i]].cnt + tr[tr[tr[u].son[i]].fail].sum;
q.push(tr[u].son[i]); // 并加入队列
} else
tr[u].son[i] =
tr[tr[u].fail]
.son[i]; // 将不存在的字典树的状态链接到了失配指针的对应状态
}
}
}
long long query(string &t) {
int u = 0;
long long ans = 0;
int L = t.length();
for (int i = 0; i < L; i++) {
u = tr[u].son[t[i] - CH]; // 转移
ans += tr[u].sum;
}
return ans;
}
};
后缀数组 和 两子串最长公共前缀
点击查看代码
int n,m,p;
int sa[N], rk[N << 1], oldrk[N << 1], id[N], cnt[N];
int height[N];
constexpr int logN = 16;
int f[logN + 1][N],Logn[N];
void init(string &s){
m = 128;
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; i++) cnt[rk[i] = s[i]]++;
for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; i--) sa[cnt[rk[i]]--] = i;
for (int w = 1;; w <<= 1, m = p) { // m = p 即为值域优化
int cur = 0;
for (int i = n - w + 1; i <= n; i++) id[++cur] = i;
for (int i = 1; i <= n; i++)
if (sa[i] > w) id[++cur] = sa[i] - w;
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; i++) cnt[rk[i]]++;
for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; i--) sa[cnt[rk[id[i]]]--] = id[i];
p = 0;
memcpy(oldrk, rk, sizeof(oldrk));
for (int i = 1; i <= n; i++) {
if (oldrk[sa[i]] == oldrk[sa[i - 1]] &&
oldrk[sa[i] + w] == oldrk[sa[i - 1] + w])
rk[sa[i]] = p;
else
rk[sa[i]] = ++p;
}
if (p == n) break; // p = n 时无需再排序
}
for (int i = 1, k = 0; i <= n; ++i) {
if (rk[i] == 0) continue;
if (k) --k;
while (s[i + k] == s[sa[rk[i] - 1] + k]) ++k;
height[rk[i]] = k;
}
Logn[2] = 1;
for (int i = 3; i < N; i++) {
Logn[i] = Logn[i / 2] + 1;
}
for (int i = 1; i <= n; i++){
f[0][i]=height[i];
}
for (int j = 1; j <= logN; j++){
for (int i = 1; i + (1 << j) - 1 <= n; i++){
f[j][i] = min(f[j - 1][i], f[j - 1][i + (1 << (j - 1))]);
}
}
}
int get(int x,int y){
x=rk[x];
y=rk[y];
if(x>y)swap(x,y);
x++;
int s = Logn[y - x + 1];
return min(f[s][x], f[s][y - (1 << s) + 1]);
}