CF1045J Moonwalk challenge 题解
不会一点字符串算法,考虑哈希。
注意到一个特殊限制是
考虑询问答案时怎么处理。我们考虑 vector
上二分维护。最后一种,可以注意到
记得用双哈希并且卡常。
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("-Ofast,fast-math,-inline")
#pragma GCC target("sse,sse2,sse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <iostream>
#include <cstdio>
#include <iomanip>
#include <map>
#include <unordered_map>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
const int N = 1e5 + 5;
const long long MOD = 998244853ll, MOD2 = 998244353ll;
int n, q;
vector<pair<int, char>> G[N];
struct Two_Hash
{
int hs1, hs2;
Two_Hash() = default;
Two_Hash(int hs1, int hs2) : hs1(hs1), hs2(hs2) {}
Two_Hash operator+(const int& x) const
{
return Two_Hash((hs1 + x) % MOD, (hs2 + x) % MOD2);
}
Two_Hash operator*(const int& x) const
{
return Two_Hash((hs1 * 1ll * x) % MOD, (hs2 * 1ll * x) % MOD2);
}
Two_Hash operator*(const Two_Hash& x) const
{
return Two_Hash((1ll * hs1 * x.hs1) % MOD, (1ll * hs2 * x.hs2) % MOD2);
}
Two_Hash operator+(const Two_Hash& x) const
{
return Two_Hash((hs1 + x.hs1) % MOD, (hs2 + x.hs2) % MOD2);
}
bool operator==(const Two_Hash& x) const
{
return hs1 == x.hs1 && hs2 == x.hs2;
}
void operator=(const int x)
{
hs1 = x;
hs2 = x;
}
};
struct Myhash
{
size_t operator()(const Two_Hash& x) const
{
return (1ll * x.hs1 * MOD + x.hs2) % MOD2;
}
};
Two_Hash f[N][101], g[N][101];
int fa[N], nfa[N][21], dis[N];
Two_Hash powe[N];
int dep[N];
static void dfs(int u, int f)
{
nfa[u][0] = f;
fa[u] = f;
dep[u] = dep[f] + 1;
for (auto& [j, c] : G[u])
{
if (j == f) continue;
::f[j][1] = c - 'a' + 1;
::g[j][1] = c - 'a' + 1;
dis[j] = dis[u] + 1;
dfs(j, u);
}
}
inline int LCA(int u, int v)
{
if (u == v) return u;
if (dep[u] < dep[v]) swap(u, v);
int k(dep[u] - dep[v]), c = 0;
while (k)
{
if (k & 1) u = nfa[u][c];
k >>= 1, c++;
}
if (u == v) return u;
for (int i = 16; i >= 0; i--)
{
if (nfa[u][i] ^ nfa[v][i]) u = nfa[u][i], v = nfa[v][i];
}
return nfa[u][0];
}
int id[N], top[N], sz[N], son[N], idx;
class TreeCut
{
public:
int pp;
vector<int> dfn;
unordered_map<Two_Hash, vector<int>, Myhash> pos;
inline void dfs1(int u, int f)
{
fa[u] = f;
sz[u] = 1;
dep[u] = dep[f] + 1;
for (auto& [j, c] : G[u])
{
if (j == f) continue;
dfs1(j, u);
sz[u] += sz[j];
if (sz[son[u]] < sz[j]) son[u] = j;
}
}
inline void dfs2(int u, int f)
{
top[u] = f;
id[u] = ++idx;
dfn.emplace_back(u);
pos[::f[u][pp]].emplace_back(idx);
if (!son[u]) return;
dfs2(son[u], f);
for (auto& [j, c] : G[u])
{
if ((j ^ fa[u]) and (j ^ son[u])) dfs2(j, j);
}
}
inline int qry(int l, int r, Two_Hash v)
{
if (!pos.count(v)) return 0;
return upper_bound(pos[v].begin(), pos[v].end(), r) - lower_bound(pos[v].begin(), pos[v].end(), l);
}
inline int query(int u, int v, Two_Hash c)
{
int res = 0;
while (top[u] ^ top[v])
{
if (dep[top[u]] < dep[top[v]]) swap(u, v);
res += qry(id[top[u]], id[u], c);
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
res += qry(id[u], id[v], c);
return res;
}
inline void build(int g)
{
pos.clear();
pp = g;
if (g == 1) dfs1(1, 1), dfs2(1, 1);
else
{
for (auto& i : dfn) pos[::f[i][pp]].emplace_back(id[i]);
}
}
}tc;
inline Two_Hash gethash(string s)
{
Two_Hash tw;
tw.hs1 = tw.hs2 = 0;
for (auto& i : s)
{
tw = (tw * 26ll + (i - 'a' + 1));
}
return tw;
}
struct Query
{
int u, v;
Two_Hash c;
int id;
Query() = default;
Query(int u, int v, Two_Hash c, int id) :u(u), v(v), c(c), id(id) {}
};
vector<Query> vq[105];
int res[N];
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
powe[0] = 1;
for (int i = 1; i < N; i++) powe[i] = powe[i - 1] * 26ll;
for (int i = 1; i < n; i++)
{
int u, v;
char c;
cin >> u >> v >> c;
G[u].emplace_back(make_pair(v, c));
G[v].emplace_back(make_pair(u, c));
}
dfs(1, 1);
for (int j = 1; j <= 16; j++)
{
for (int i = 1; i <= n; i++) nfa[i][j] = nfa[nfa[i][j - 1]][j - 1];
}
auto get_k_fa = [&](int u, int k) -> int
{
int c = 0;
while (k)
{
if (k & 1) u = nfa[u][c];
c++;
k >>= 1;
}
return u;
};
auto get_dis = [&](int u, int v) -> int
{
return dis[u] + dis[v] - 2 * dis[LCA(u, v)];
};
for (int j = 1; j <= 100; j++)
{
for (int i = 1; i <= n; i++)
{
int ff = get_k_fa(i, j - 1);
f[i][j] = (f[ff][1] * powe[j - 1] + f[i][j - 1]);
g[i][j] = (g[i][j - 1] * 26ll + g[ff][1]);
}
}
cin >> q;
for (int i = 1; i <= q; i++)
{
int u, v;
string s;
cin >> u >> v >> s;
int L(LCA(u, v));
Two_Hash rr(gethash(s));
// L->v
int rv = v;
int ans = 0;
int dul = get_dis(u, L), dul2 = get_dis(v, L), len = s.size();
if (dul2 <= len)
{
int rd(dul2);
int dd = dul + dul2;
vector<int> tot;
for (; v != L; v = fa[v])
{
if (dd < len) break;
dd--;
tot.emplace_back(v);
rd--;
}
v = L;
dd = get_dis(v, u);
int p, npos;
if (dd >= len)
{
tot.emplace_back(L);
rd--;
}
reverse(tot.begin(), tot.end());
if (tot.empty()) continue;
p = len - rd - 1;
npos = get_k_fa(u, dul - p);
for (auto& v : tot)
{
rd++;
ans += ((g[npos][len - rd] * powe[rd] + f[v][rd]) == rr);
npos = fa[npos];
}
}
else
{
int lens = get_dis(v, L);
int pos(get_k_fa(v, lens - len - 1));
vq[len].emplace_back(Query(pos, v, rr, i));
v = nfa[pos][0];
int rd = get_dis(v, L);
int dd = get_dis(v, u);
vector<int> tot;
for (; v != L; v = fa[v])
{
if (dd < len) break;
dd--;
tot.emplace_back(v);
rd--;
}
v = L;
dd = get_dis(v, u);
int p, npos;
if (dd >= len)
{
tot.emplace_back(L);
rd--;
}
reverse(tot.begin(), tot.end());
if (tot.empty()) continue;
p = len - rd - 1;
npos = get_k_fa(u, dul - p);
for (auto& v : tot)
{
rd++;
ans += ((g[npos][len - rd] * powe[rd] + f[v][rd]) == rr);
npos = fa[npos];
}
}
// L->u
reverse(s.begin(), s.end());
v = rv;
if (dul > len)
{
vq[len].emplace_back(Query(u, get_k_fa(u, dul - len - 1), gethash(s), i));
}
res[i] = ans;
}
for (int i = 1; i <= 100; i++)
{
if (!vq[i].size()) continue;
tc.build(i);
for (auto& [u, v, c, id] : vq[i])
{
res[id] += tc.query(u, v, c);
}
} // 1
for (int i = 1; i <= q; i++) cout << res[i] << "\n";
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现