1 条题解
-
0
题解
把老师要读的串建成 AC 自动机,
idx[i]
记录第i
个点名串在自动机中的结点。失配指针构成一棵树,第一次 DFS 计算各结点的深度、子树大小以及sum[u]
——表示从根走到u
时匹配到的模式串数量;第二次 DFS 进行重链剖分,得到每个结点的dfn
和重链顶部,便于我们在失配树上做 LCA 和子树查询。对每个喵星人,把姓与名中间插入一个不会在其它字符串出现的哨兵值后拼接成一个序列,沿 AC 自动机逐字符转移,把走到的结点按
dfn
序排序,并依次加入树状数组:遇到一条新路径时在当前结点加一,在前一个结点与当前结点的 LCA 处减一,这样可以用差分方式维护当前有哪些模式出现过;同时利用预处理好的sum[u]
就能把该喵星人被点到的次数累加到ans[i]
。处理完全部人名后,只需对每个点名串查询其对应结点子树上的计数和,就可以得到回答该次点名的喵星人数。最后输出所有点名串的结果以及每个喵星人累计被点到的次数。#include <bits/stdc++.h> using i64 = long long; constexpr int N = 1E5 + 5; std::vector<int> G[N]; struct ACAM { std::map<int, int> trie[N]; int tot, idx[N], fail[N], end[N]; void insert(const std::basic_string<int> & s, int id) { int u = 0; for (auto v : s) { if (trie[u].find(v) == trie[u].end()) trie[u][v] = ++tot; u = trie[u][v]; } end[u]++, idx[id] = u; } void build() { std::queue<int> q; for (auto [v, i] : trie[0]) { q.push(i); } while (!q.empty()) { int u = q.front(); q.pop(); for (auto [c, v] : trie[u]) { int j = fail[u]; while (j > 0 && trie[j].find(c) == trie[j].end()) j = fail[j]; if (trie[j].find(c) != trie[j].end()) fail[v] = trie[j][c]; q.push(v); } } for (int i = 1; i <= tot; i++) { G[fail[i]].push_back(i); } } size_t size() const { return tot + 1; } }ACAM; int n, m; int sum[N]; int dep[N], siz[N], son[N], fa[N]; void dfs1(int u) { son[u] = -1; siz[u] = 1; for (auto v : G[u]) { fa[v] = u, dep[v] = dep[u] + 1, sum[v] = sum[u] + ACAM.end[v]; dfs1(v); siz[u] += siz[v]; if (son[u] == -1 || siz[v] > siz[son[u]]) { son[u] = v; } } } int top[N], dfn[N], dfn_cnt; void dfs2(int u, int x) { top[u] = x; dfn[u] = ++dfn_cnt; if (son[u] != -1) dfs2(son[u], x); for (auto v : G[u]) { if (v != son[u]) { dfs2(v, v); } } } int LCA(int u, int v) { for (; top[u] != top[v]; u = fa[top[u]]) { if (dep[top[u]] < dep[top[v]]) std::swap(u, v); } return dep[u] < dep[v]? u: v; } std::basic_string<int> s[N]; int ans[N]; struct BIT { int t[N]; size_t n; void resize(const size_t & _sz = 0) { memset(t, 0, sizeof(int) * (_sz + 1)); n = _sz; } int lowbit(int x) const { return x & -x; } void update(int x, int val) { for (; x <= n; x += lowbit(x)) { t[x] += val; } } int query(int x) { int ans = 0; for (; x; x -= lowbit(x)) ans += t[x]; return ans; } int query(int l, int r) { return query(r) - query(l - 1); } }t; int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cin >> n >> m; for (int i = 1; i <= n; i++) { int l; std::cin >> l; for (int j = 1; j <= l; j++) { int x; std::cin >> x; s[i] += x; } s[i] += -1; std::cin >> l; for (int j = 1; j <= l; j++) { int x; std::cin >> x; s[i] += x; } } for (int i = 1; i <= m; i++) { std::basic_string<int> t; int l; std::cin >> l; for (int j = 1; j <= l; j++) { int x; std::cin >> x; t += x; } ACAM.insert(t, i); } ACAM.build(); t.resize(ACAM.size()); dfs1(0), dfs2(0, 0); for (int i = 1; i <= n; i++) { std::vector<int> vec; int u = 0; for (auto c : s[i]) { while (u > 0 && ACAM.trie[u].find(c) == ACAM.trie[u].end()) { u = ACAM.fail[u]; } if (ACAM.trie[u].find(c) != ACAM.trie[u].end()) u = ACAM.trie[u][c]; vec.push_back(u); } std::sort(vec.begin(), vec.end(), [&](const int & x, const int & y) { return dfn[x] < dfn[y]; }); t.update(dfn[vec[0]], 1); ans[i] += sum[vec[0]]; for (int j = 1; j < (int)vec.size(); j++) { int lca = LCA(vec[j], vec[j - 1]); ans[i] += sum[vec[j]], ans[i] -= sum[lca]; t.update(dfn[vec[j]], 1), t.update(dfn[lca], -1); } } for (int i = 1; i <= m; i++) { int u = ACAM.idx[i]; std::cout << t.query(dfn[u], dfn[u] + siz[u] - 1) << "\n"; } for (int i = 1; i <= n; i++) { std::cout << ans[i] << " \n"[i == n]; } return 0; }
- 1
信息
- ID
- 3249
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 9
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者