专题链接:https://codeforces.com/group/5yyKg9gx7m/contest/269717/problem/E
思路
创建一个kind数组,记入从根节点到i的H牛的数量,对于每一个访问,如果这条路上H牛的数量==走过的点数,则只能喝到H牛的奶,如果H牛的数量为0,则只能喝到G牛的牛奶。
对于点与点之间的距离,我们用倍增LCA求出即可。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#define ll long long
using namespace std;
int N, M;
int num = 0;
char str[100001];
int kind[100001];
int fa[100001];
int dp[100001][20];
int dep[100001];//记入每个节点的深度
int head[100001];//记入经过i的点的第一条边的存储位置
struct edge
{
int next;
int to;
}arr[200001];
void edge_add(int from,int to)
{
num++;
arr[num].next = head[from];
arr[num].to = to;
head[from] = num;
}
void dfs(int x)
{
for (int i = head[x]; i; i=arr[i].next)
{
int to = arr[i].to;
if (!dep[to])
{
fa[to] = x;
dep[to] = dep[x] + 1;
kind[to]= kind[to]+kind[x];//dfs时别忘了更新kind数组
dfs(to);
}
}
}
int LCA(int x, int y)
{
if (dep[x] < dep[y])
swap(x, y);
for (int i = 19; i >= 0; i--)
if (dep[y] <= dep[x] - (1 << i))
x = dp[x][i];
if (x == y)
return x;
for (int i = 19; i >= 0; i--)
{
if (dp[x][i] != dp[y][i])
{
x = dp[x][i];
y = dp[y][i];
}
}
return fa[x];
}
int main()
{
cin >> N >> M;
scanf("%s", str + 1);
for (int i = 1; i <= N; i++)
{
if (str[i] == 'H')
kind[i] = 1;
else
kind[i] = 0;
}
for (int i = 1; i <= N-1; i++)
{
int from, to;
scanf("%d%d", &from, &to);
edge_add(from, to);
edge_add(to,from);
}
dep[1] = 1;//设1为根节点
fa[1] = 0;
dfs(1);
for (int i = 1; i <= N; i++)//构造ST表
dp[i][0]=fa[i];
for (int j = 1; j <= 19; j++)
for (int i = 1; i <= N; i++)
dp[i][j] = dp[dp[i][j - 1]][j - 1];
while (M--)
{
int x, y;
char ch;
scanf("%d%d", &x, &y);
scanf(" %c", &ch);
int t = LCA(x, y);
int ans = kind[x]-kind[t] + kind[y]-kind[fa[t]];//计算出这条路上H牛的数量
if (ch == 'G')
{
if (ans != 1+dep[x]+dep[y]-2*dep[t])//计算出这两路上的农村数
printf("1");
else
printf("0");
}
else
{
if (ans!=0)
printf("1");
else
printf("0");
}
}
return 0;
}