【题目大意】
有一棵n(1<=n<=10^5)个节点的树,每个节点有个标志要么为H,要么为G,有M(1<=M<=10 ^5)个询问,每组询问(x,y,c),若x到y的路径上有c,那么输出1,否则输出0
【解题思路】
不妨以1为根节点,h[i]表示根节点1到x的路径上H的数量,g[i]表示根节点1到x的路径上H的数量。
t为x与y的最近公共祖先,fa为t的父亲
则x到y的路径上H的数量等于h[x]-h[t]+h[y]-h[fa]
G的数量同理
【代码】
#include <cstdio>
#include <vector>
#include <iostream>
#include <string>
using namespace std;
vector <int> a[101010];
int anc[101010][22];
string st;
int n,m;
int h[101010],g[101010],d[101010];
void dfs(int x,int fa,int dep)
{
anc[x][0]=fa;
h[x]+=h[fa];
g[x]+=g[fa];
d[x]=dep;
for (int i=0;i<a[x].size();i++)
{
int son=a[x][i];
if (son!=fa) dfs(son,x,dep+1);
}
}
void BZ()
{
for (int i=1;i<=20;i++)
for (int x=1;x<=n;x++)
anc[x][i]=anc[anc[x][i-1]][i-1];
}
int LCA(int x,int y)
{
if (d[x]<d[y]) swap(x,y);
if (x==y) return x;
if (d[x]!=d[y])
{
for (int i=20;i>=0;i--)
if (d[anc[x][i]]>=d[y]) x=anc[x][i];
}
if (x==y) return x;
if (x!=y)
{
for (int i=20;i>=0;i--)
{
int xx=anc[x][i];
int yy=anc[y][i];
if (xx==yy) continue;
x=xx;
y=yy;
}
}
return anc[x][0];
}
int main()
{
scanf("%d%d",&n,&m);
cin>>st;
for (int i=0;i<st.size();i++)
{
if (st[i]=='H') h[i+1]=1;
else g[i+1]=1;
}
for (int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
a[x].push_back(y);
a[y].push_back(x);
}
dfs(1,0,1);
BZ();
for (int i=1;i<=m;i++)
{
int x,y;
char ch;
scanf("%d%d",&x,&y);
int t=LCA(x,y);
cin>>ch;
if (ch=='H')
{
int sum=h[x]-h[t];
sum+=h[y]-h[anc[t][0]];
if (sum==0) printf("0");
else printf("1");
}else
{
int sum=g[x]-g[t];
sum+=g[y]-g[anc[t][0]];
if (sum==0) printf("0");
else printf("1");
}
}
return 0;
}