P8947 Angels & Demons
P8947 Angels & Demons
因为查询和所有询问串相关,所以在加入询问串时,它对每个模板串的贡献都要考虑到。因此只能对所有模板串统一建出结构。
因为查询和模板串子串相关,所以这个结构需要描述所有模板串的所有子串。我们考虑广义 SAM。
加入询问串
- 存在
p 在该子串对应状态的子树内(不包括自身)。 - 存在
p 等于该子串的对应状态,且子串长度不大于对应的L 。
相同的
说白了,就是把 Divljak 放在广义 SAM 上。
时空复杂度线性对数加线性字符集。
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
constexpr int N = 1e6 + 5;
constexpr int M = N << 4;
constexpr int K = 20;
constexpr int S = 26;
namespace GSAM {
int node, cnt = 1;
int son[N][S], len[N], fa[N], anc[K][N];
int ins(int p, int it) {
int to = son[p][it];
if(to && len[p] + 1 == len[to]) return to;
int cur = ++cnt;
len[cur] = len[p] + 1;
while(!son[p][it]) son[p][it] = cur, p = fa[p];
if(!p) return fa[cur] = 1, cur;
int q = son[p][it];
if(len[p] + 1 == len[q]) return fa[cur] = q, cur;
int cl = ++cnt;
len[cl] = len[p] + 1;
memcpy(son[cl], son[q], S << 2);
fa[cl] = fa[q], fa[q] = fa[cur] = cl;
while(son[p][it] == q) son[p][it] = cl, p = fa[p];
return to ? cl : cur;
}
void build() {
for(int i = 0; i < K; i++)
for(int j = 1; j <= cnt; j++) {
if(i) anc[i][j] = anc[i - 1][anc[i - 1][j]];
else anc[i][j] = fa[j];
}
}
int locate(int pos, int L) {
for(int i = K - 1; ~i; i--) {
int q = anc[i][pos];
if(len[q] >= L) pos = q;
}
return pos;
}
void path(char *s, int m, auto P) {
int L = 0, p = 1;
for(int i = 1; i <= m; i++) {
int it = s[i] - 'a';
while(p > 1 && !son[p][it]) L = len[p = fa[p]];
if(son[p][it]) L++, p = son[p][it];
P[i - 1] = {p, L};
}
}
}
namespace BIT {
int c[N];
void add(int x, int v) {
while(x < N) c[x] += v, x += x & -x;
}
int query(int x) {
int s = 0;
while(x) s += c[x], x -= x & -x;
return s;
}
int query(int l, int r) {
return query(r) - query(l - 1);
}
}
namespace SEG {
int node, R[N], ls[M], rs[M], val[M];
void modify(int l, int r, int p, int &x) {
if(!x) x = ++node;
val[x]++;
if(l == r) return;
int m = l + r >> 1;
if(p <= m) modify(l, m, p, ls[x]);
else modify(m + 1, r, p, rs[x]);
}
int query(int l, int r, int ql, int qr, int x) {
if(ql <= l && r <= qr || !x) return val[x];
int m = l + r >> 1, ans = 0;
if(ql <= m) ans = query(l, m, ql, qr, ls[x]);
if(m < qr) ans += query(m + 1, r, ql, qr, rs[x]);
return ans;
}
}
using GSAM::fa;
using GSAM::len;
using GSAM::cnt;
int n, q, lg[N], w0, A, B, C = 1;
string str[N];
vector<int> pos[N], e[N];
int dn, dfn[N], dep[N], sz[N], mi[K][N];
void dfs(int id) {
dfn[id] = ++dn, sz[id] = 1;
mi[0][dn] = fa[id], dep[id] = dep[fa[id]] + 1;
for(int it : e[id]) dfs(it), sz[id] += sz[it];
}
bool isa(int u, int v) {
return dfn[u] <= dfn[v] && dfn[v] < dfn[u] + sz[u];
}
int get(int x, int y) {
return dep[x] < dep[y] ? x : y;
}
int lca(int u, int v) {
if(u == v) return u;
if((u = dfn[u]) > (v = dfn[v])) swap(u, v);
int d = lg[v - u++];
return get(mi[d][u], mi[d][v - (1 << d) + 1]);
}
int main() {
#ifdef ALEX_WEI
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> q >> w0;
if(w0) cin >> A >> B >> C;
for(int i = 1, lst = 1; i <= n; i++, lst = 1) {
cin >> str[i], pos[i].resize(str[i].size());
for(int j = 0; j < str[i].size(); j++) {
lst = pos[i][j] = GSAM::ins(lst, str[i][j] - 'a');
}
}
GSAM::build();
for(int i = 2; i <= cnt; i++) e[fa[i]].push_back(i);
for(int i = 2; i <= cnt; i++) lg[i] = lg[i >> 1] + 1;
dfs(1), assert(cnt == dn);
for(int i = 1; i <= lg[cnt]; i++) {
for(int j = 1; j + (1 << i) - 1 <= cnt; j++) {
mi[i][j] = get(mi[i - 1][j], mi[i - 1][j + (1 << i - 1)]);
}
}
for(int _ = 1, lst = 0; _ <= q; _++) {
int op, x = (1ll * A * lst + B) % C;
cin >> op;
if(op == 1) {
static char s[N];
cin >> s + 1;
int m = strlen(s + 1);
if(w0) {
for(int i = 1; i <= m; i++) {
swap(s[i], s[x % m + 1]);
x = (1ll * A * x + B) % C;
}
}
static pair<int, int> P[N], Q[N];
GSAM::path(s, m, P);
sort(P, P + m, [&](auto a, auto b) {
return a.fi != b.fi ? dfn[a.fi] < dfn[b.fi] : a.se < b.se;
});
int c = 0;
for(int i = 0; i < m; i++) {
while(c && isa(Q[c - 1].fi, P[i].fi)) c--;
Q[c++] = P[i];
}
if(c == 1 && Q[0].fi == 1) continue;
for(int i = 0; i < c; i++) {
int id = Q[i].fi;
BIT::add(dfn[fa[id]], 1);
if(i) BIT::add(dfn[lca(fa[id], Q[i - 1].fi)], -1);
SEG::modify(len[fa[id]] + 1, len[id], Q[i].se, SEG::R[id]);
}
}
else {
int p, l, r;
cin >> p >> l >> r;
if(w0) {
p = (p + x) % n + 1;
x = (1ll * A * x + B) % C;
l = (l + x) % str[p].size() + 1;
x = (1ll * A * x + B) % C;
r = (r + x) % str[p].size() + 1;
x = (1ll * A * x + B) % C;
if(l > r) swap(l, r);
}
int L = r - l + 1;
p = GSAM::locate(pos[p][r - 1], L);
int ans = BIT::query(dfn[p], dfn[p] + sz[p] - 1);
ans += SEG::query(len[fa[p]] + 1, len[p], L, len[p], SEG::R[p]);
cout << (lst = ans) << "\n";
}
}
cerr << 1e3 * clock() / CLOCKS_PER_SEC << " ms\n";
return 0;
}