[题解] [JSOI2015] 送礼物
题面
题解
经典套路, 用树上前缀和的方式建出可持久化 Trie 树
询问就树上差分一下就行
Code
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
const int N = 100005;
using namespace std;
int n, m, head[N], cnt, cnte, rt[N];
struct edge { int to, nxt, len; string s; } e[N << 1];
struct node { int ch[26], val; } t[N * 32];
template < typename T >
inline T read()
{
T x = 0, w = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * w;
}
inline void adde(int u, int v, string s) { e[++cnte] = (edge) { v, head[u], s.size(), s }, head[u] = cnte; }
void insert(int &p, int o, int x, int len, string s)
{
t[p = ++cnt] = t[o], t[p].val++;
if(x < len) insert(t[p].ch[s[x] - 'a'], t[o].ch[s[x] - 'a'], x + 1, len, s);
}
namespace Treepou
{
int sz[N], dep[N], fa[N], son[N], top[N];
void dfs1(int u, int pa)
{
sz[u] = 1, dep[u] = dep[pa] + 1, fa[u] = pa;
for(int v, i = head[u]; i; i = e[i].nxt)
{
v = e[i].to; if(v == pa) continue;
insert(rt[v], rt[u], 0, e[i].len, e[i].s);
dfs1(v, u), sz[u] += sz[v];
if(sz[v] > sz[son[u]]) son[u] = v;
}
}
void dfs2(int x, int y)
{
top[x] = y; if(!son[x]) return;
dfs2(son[x], y);
for(int i = head[x]; i; i = e[i].nxt)
if(e[i].to != fa[x] && e[i].to != son[x]) dfs2(e[i].to, e[i].to);
}
int LCA(int u, int v)
{
while(top[u] ^ top[v]) dep[top[u]] > dep[top[v]] ? u = fa[top[u]] : v = fa[top[v]];
return dep[u] < dep[v] ? u : v;
}
};
using namespace :: Treepou;
int query(int p, string s)
{
int len = s.size();
for(int i = 0; i < len; i++)
p = t[p].ch[s[i] - 'a'];
return t[p].val;
}
int main()
{
n = read <int> ();
string s; rt[1] = ++cnt;
for(int u, v, i = 1; i < n; i++)
{
u = read <int> (), v = read <int> (), cin>>s;
adde(u, v, s), adde(v, u, s);
}
dfs1(1, 0), dfs2(1, 1);
m = read <int> ();
for(int u, v, i = 1; i <= m; i++)
{
u = read <int> (), v = read <int> (), cin>>s;
printf("%d\n", query(rt[u], s) + query(rt[v], s) - 2 * query(rt[LCA(u, v)], s));
}
return 0;
}