https://ac.nowcoder.com/acm/contest/8755/J
思路:首先预处理一下树上前缀和,即从树根到当前节点,每种字母的个数有多少。
那么对于每次询问,我们只需要求出LCA,然后对于两点之间每种类型字母的个数就是
sum(x)+sum(y)-sum(LCA)-sum(FA[LCA])
然后每种类型字母都取偶数加起来,在看看有没有奇数就好了。
关于树上前缀和式子计算右转https://blog.csdn.net/qq_43563669/article/details/109902855
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int head[N], tot, depth[N], fa[N][22], lg[N];
struct Node
{
int t, nex;
} e[N << 1];
void add(int x, int y)
{
e[++tot].t = y;
e[tot].nex = head[x];
head[x] = tot;
}
void dfs(int now, int fath)
{
fa[now][0] = fath;
depth[now] = depth[fath] + 1;
for (int i = 1; i <= lg[depth[now]]; ++i)
fa[now][i] = fa[fa[now][i - 1]][i - 1];
for (int i = head[now]; i; i = e[i].nex)
if (e[i].t != fath)
dfs(e[i].t, now);
}
int LCA(int x, int y)
{
if (depth[x] < depth[y])
swap(x, y);
while (depth[x] > depth[y])
x = fa[x][lg[depth[x] - depth[y]] - 1];
if (x == y)
return x;
for (int k = lg[depth[x]] - 1; k >= 0; --k)
if (fa[x][k] != fa[y][k])
x = fa[x][k], y = fa[y][k];
return fa[x][0];
}
void init()
{
tot = 0;
memset(head, 0, sizeof(head));
memset(fa, 0, sizeof(fa));
memset(depth, 0, sizeof(depth));
}
int cnt[N][26];
int FA[N];
char str[N];
void DFS(int x, int f)
{
FA[x] = f;
cnt[x][str[x] - 'a']++;
for (int i = head[x]; i; i = e[i].nex)
{
int to = e[i].t;
if (to == f)
continue;
for (int j = 0; j < 26; j++)
cnt[to][j] += cnt[x][j];
DFS(to, x);
}
}
int main()
{
int n, m, s;
scanf("%d", &n);
init();
for (int i = 1; i <= n - 1; ++i)
{
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
scanf("%s", str + 1);
for (int i = 1; i <= n; ++i)
lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
dfs(1, 0);
DFS(1, 0);
cin >> m;
while (m--)
{
int x, y;
cin >> x >> y;
int lca = LCA(x, y);
int sum = 0, odd = 0;
int Q[26] = {0};
for (int i = 0; i < 26; i++)
{
Q[i] =cnt[x][i] + cnt[y][i] - cnt[lca][i] - cnt[FA[lca]][i];
}
for (int i = 0; i < 26; i++)
{
sum += Q[i] / 2 * 2;
odd |= Q[i] & 1;
}
cout << sum + odd << endl;
}
return 0;
}