rt,树剖套平衡树,本题 85pts,弱化版 45pts,快哭了
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#define G __gnu_pbds
#define TOSNU tree_order_statistics_node_update
#define rnk order_of_key
#define lb lower_bound
#define pii pair<int, int>
#define P make_pair
#define fi first
#define se second
#define vec vector
#define umap unordered_map
using namespace std; const int N = 1e5 + 5, inf = 1e9; typedef string str;
vec<int> g[N]; vector<pii> bin; vec<str> a[N]; str op1, op2, op3;
int n, m, dep[N], top[N], fa[N], hson[N], idx, dfn[N], siz[N];
umap<str, G::tree<pii, G::null_type, less<pii>, G::rb_tree_tag, G::TOSNU>> rbt;
void dfs1(int u) {
siz[u] = 1;
for (int v : g[u])
if (v != fa[u]) dep[v] = dep[fa[v] = u] + 1, dfs1(v), siz[u] += siz[v];
}
void dfs2(int u) {
for (int v : g[u]) {
if (v == fa[u]) continue;
if ((siz[v] << 1) > siz[u]) top[hson[u] = v] = top[u];
else top[v] = v; dfs2(v);
}
}
void dfs3(int u) {
dfn[u] = ++idx; int t = 0; for (str s : a[u]) rbt[s].insert(P(idx, ++t));
if (hson[u]) dfs3(hson[u]);
for (int v : g[u]) if (v != fa[u] && v != hson[u]) dfs3(v);
}
int LCA(int u, int v) {
while (top[u] != top[v])
if (dep[top[u]] > dep[top[v]]) u = fa[top[u]]; else v = fa[top[v]];
return dep[u] < dep[v] ? u : v;
}
int chain(int u, int v, str suf) {
int ret = 0;
while (top[u] != top[v]) {
ret += rbt[suf].rnk(P(dfn[u], inf)) - rbt[suf].rnk(P(dfn[top[u]], 0));
u = fa[top[u]];
}
return ret + rbt[suf].rnk(P(dfn[u], inf)) - rbt[suf].rnk(P(dfn[v], 0));
}
void erase(int u, int v, str suf) {
while (top[u] != top[v]) {
auto l = rbt[suf].lb(P(dfn[top[u]], 0)), r = rbt[suf].lb(P(dfn[u], inf));
bin.clear(); for (auto it = l; it != r; ++it) bin.emplace_back(*it);
for (pii i : bin) rbt[suf].erase(i); u = fa[top[u]];
}
auto l = rbt[suf].lb(P(dfn[v],0)), r = rbt[suf].lb(P(dfn[u], inf));
bin.clear(); for (auto it = l; it != r; ++it) bin.emplace_back(*it);
for (pii i : bin) rbt[suf].erase(i);
}
int query(int u, int v, int lca, str suf) {
if (lca == u) return chain(v, u, suf);
if (lca == v) return chain(u, v, suf);
return chain(u, hson[lca], suf) + chain(v, lca, suf);
}
void del(int u, int v, int lca, str suf) {
if (lca == u) return erase(v, u, suf), void();
if (lca == v) return erase(u, v, suf), void();
erase(u, hson[lca], suf), erase(v, lca, suf);
}
signed main() {
cin.tie(0), cout.tie(0), ios::sync_with_stdio(0); cin >> n >> m;
for (int i = 1, u, v; i < n; ++i)
cin >> u >> v, g[u].emplace_back(v), g[v].emplace_back(u);
for (int i = 1, x; i <= n; ++i) {
cin >> x; for (str tmp; x--;) cin >> tmp, a[i].emplace_back(tmp);
}
dfs1(1), dfs2(top[1] = 1), dfs3(1);
for (int i = 1, u, v, lca; i <= m; ++i) {
cin >> op1 >> op2 >> u >> v; lca = LCA(u, v);
if (op2 == "/p")
cout << dep[u] + dep[v] - (dep[lca] << 1) << '\n';
else {
cin >> op3; op3 = op3.substr(2);
cout << query(u, v, lca, op3) << '\n';
if (op1 == "del") del(u, v, lca, op3);
}
}
return 0;
}