rt.思路是先去掉小数点,考虑路径上数相乘后末尾 0 的个数,我是维护 2 和 5 的幂次取较小者。然后记录总小数点偏移量,比较两者大小。好像都可以通过 LCA 简单计算。但是始终只能过一个点。求 hack/求调。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=400010;
const int maxm=500010;
int n,m,x,y,tot=0;
int a[maxn],head[maxn],to[maxm],nxt[maxm];
int dep[maxn],fa[maxn][25],lg[maxn],cnt[maxn],ver[maxn];
double z;
inline int calc2(int x)//2的幂次
{
int cal=0;
while(x && x%2==0)cal++,x/=2;
return cal;
}
inline int calc5(int x)//5的幂次
{
int cal=0;
while(x && x%5==0)cal++,x/=5;
return cal;
}
int sum[maxn],two[maxn],five[maxn];//sum:总小数点位数,two,five:末尾0的个数
inline void add(int x,int y,int z,int p)//p:小数点位数
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;//模板
ver[tot]=z;
cnt[tot]=p;
}
inline void dfs(int x,int f)
{
dep[x]=dep[f]+1;
fa[x][0]=f;
for(int i=1;(1<<i)<=dep[x];i++)
{
fa[x][i]=fa[fa[x][i-1]][i-1];
}
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f)continue;
sum[y]=sum[x]+cnt[i];
two[y]=two[x]+calc2(ver[i]);
five[y]=five[x]+calc5(ver[i]);
dfs(y,x);
}
}
inline int LCA(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
while(dep[x]>dep[y])x=fa[x][lg[dep[x]-dep[y]]-1];
if(x==y)return x;
for(int i=lg[dep[x]];i>=0;i--)
{
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
signed main()
{
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<n;i++)
{
scanf("%lld%lld%lf",&x,&y,&z);
int p=0;
while(z!=floor(z))z*=10,p++;//小数点位数
add(x,y,(int)z,p);
add(y,x,(int)z,p);
}
dfs(1,0);
for(int i=1;i<=n;++i)
{
lg[i]=lg[i-1]+(1<<lg[i-1]==i);//预处理log
}
while(m--)
{
scanf("%lld%lld",&x,&y);
int flo=sum[x]+sum[y]-2*sum[LCA(x,y)];
int twos=two[x]+two[y]-2*two[LCA(x,y)]+calc2(a[x]);
int fives=five[x]+five[y]-2*five[LCA(x,y)]+calc5(a[x]);
int ten=min(twos,fives);
if(ten>=flo)printf("Yes\n");
else printf("No\n");
}
return 0;
}
/*
in:
5 5
7 8 10 1 4
1 2 0.1
2 3 0.4
3 4 0.25
4 5 0.4
1 2
2 4
1 3
3 5
1 5
out:
No
No
No
Yes
No
*/