[JSOI2015] 字符串树

给出 \(n\) 个点的树,边上有字符串 \(s\),\(q\) 次询问 \(u,v\) 两点路径上有多少边的字符串以字符串 \(t\) 为前缀。
\(n,q\le 10^5\),\(|s_i|\le 10\)。
注意到 \(|s_i|\le 10\),即本质不同的前缀不会超过 \(10^6\) 种。于是先边转点,然后运用 P5838 的套路,有两种方法:
-
【方法一】
对每种字符串建立动态开点线段树,线段树上的区间维护对应的 \(dfn\) 序区间内该前缀的出现次数。跳链时在对应前缀的线段树上查询。
时间复杂度为 \(\mathcal{O}(q\log ^2 n)\),空间复杂度为 \(\mathcal{O}\left(\left(\sum\limits_{i=1}^ns_i\right)\times \log n\right)\)。
可以参考我 P5838 的题解。
-
【方法二】
对每种前缀开一个
vector,按从小到大的顺序存放具有该前缀节点的 \(dfn\) 序。跳链时,设当前跳到点 \(u\),二分出 \(l\) 表示第一个大于等于 \(dfn_{top_u}\) 的值的位置,\(r\) 表示最后一个不超过 \(dfn_u\) 的位置,则该重链的贡献为 \(r-l+1\)。时间复杂度为 \(\mathcal{O}(q\log^2 n)\),空间复杂度为 \(\mathcal{O}\left(\sum\limits_{i=1}^ns_i\right)\)。
可以参考我 CF463E 的题解。
相比之下,【方法一】空间更劣,常数更大,但是可以支持更多的修改操作。【方法二】空间较优,常数较小,但是在修改方面有一定的局限性。
给的是【方法二】的代码。
#include <bits/stdc++.h>
#define str string
#define vec vector
#define P pair
#define eb emplace_back
#define fi first
#define se second
#define bg begin
#define ed end
using namespace std; const int N = 1e5 + 5;
int n, q, dep[N], top[N], siz[N], fa[N], dfn[N], id, hson[N];
map<str, vec<int>> mp; str s, t; vec<P<int, str>> g[N]; str col[N];
void dfs1(int u) {
siz[u] = 1;
for (auto i : g[u]) {
if (i.fi == fa[u]) continue;
col[i.fi] = i.se, dep[i.fi] = dep[fa[i.fi] = u] + 1;
dfs1(i.fi), siz[u] += siz[i.fi];
}
}
void dfs2(int u) {
for (auto i : g[u])
if (i.fi != fa[u]) {
if ((siz[i.fi] << 1) > siz[u]) top[hson[u] = i.fi] = top[u];
else top[i.fi] = i.fi;
dfs2(i.fi);
}
}
void dfs3(int u) {
dfn[u] = ++id, t = ""; int l = col[u].size();
for (int i = 0; i < l; ++i) t += col[u][i], mp[t].eb(id);
if (hson[u]) dfs3(hson[u]);
for (auto i : g[u]) {
if (i.fi == fa[u] || i.fi == hson[u]) continue; dfs3(i.fi);
}
}
int query(int x, int y, str k) {
if (mp.find(k) == mp.end()) return 0; int ret = 0;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
int u = lower_bound(mp[k].bg(), mp[k].ed(), dfn[top[x]]) - mp[k].bg();
int v = upper_bound(mp[k].bg(), mp[k].ed(), dfn[x]) - mp[k].bg() - 1;
ret += v - u + 1; x = fa[top[x]];
}
if (x == y) return ret;//有个 shaber 忘记处理同一重链的情况了,我不说是谁。
if (dep[x] > dep[y]) swap(x, y);
int u = lower_bound(mp[k].bg(), mp[k].ed(), dfn[x] + 1) - mp[k].bg();
int v = upper_bound(mp[k].bg(), mp[k].ed(), dfn[y]) - mp[k].bg() - 1;
return ret + v - u + 1;
}
signed main() {
cin.tie(0), cout.tie(0), ios::sync_with_stdio(0); cin >> n;
for (int i = 1, u, v; i < n; ++i)
cin >> u >> v >> s, g[u].eb(v, s), g[v].eb(u, s);
dfs1(1), dfs2(top[1] = 1), dfs3(1); cin >> q;
for (int u, v; q--;) cin >> u >> v >> s, cout << query(u, v, s) << '\n';
return 0;
}

浙公网安备 33010602011771号