题意:
给你一个 n 个节点的树(也就是一个无环连通无向图),节点编号从 0 到 n - 1 ,
且恰好有 n - 1 条边,每个节点有一个值。树的 根节点 为 0 号点。
给你一个整数数组 nums 和一个二维数组 edges 来表示这棵树。
nums[i] 表示第 i 个点的值,edges[j] = [uj, vj] 表示节点 uj 和节点 vj 在树中有一条边。
当 gcd(x, y) == 1 ,我们称两个数 x 和 y 是 互质的 ,其中 gcd(x, y) 是 x 和 y 的 最大公约数 。
从节点 i 到 根 最短路径上的点都是节点 i 的祖先节点。
一个节点 不是 它自己的祖先节点。
请你返回一个大小为 n 的数组 ans ,
其中 ans[i]是离节点 i 最近的祖先节点且满足 nums[i] 和 nums[ans[i]] 是 互质的 ,
如果不存在这样的祖先节点,ans[i] 为 -1 。
数据范围:
nums.length == n
1 <= nums[i] <= 50
1 <= n <= 105
edges.length == n - 1
edges[j].length == 2
0 <= uj, vj < n
uj != vj
解法:
观察到val的大小只有50,
从根开始dfs,开50个桶记录dfs树链的所有值,
对于当前数x,直接[1,50]枚举值,判断祖先是否有这些值,
有的话更新答案即可.
code:
const int maxm=1e5+5;
vector<int>c[55];
vector<int>g[maxm];
int d[maxm];
vector<int>ans;
class Solution {
public:
void dfs(vector<int>& a,int x,int fa){
ans[x]=-1;
for(int i=1;i<=50;i++){
int len=c[i].size();
if(len&&__gcd(a[x],i)==1){
if(ans[x]==-1||d[ans[x]]<d[c[i][len-1]]){
ans[x]=c[i][len-1];
}
}
}
c[a[x]].push_back(x);
for(int v:g[x]){
if(v==fa)continue;
d[v]=d[x]+1;
dfs(a,v,x);
}
c[a[x]].pop_back();
}
vector<int> getCoprimes(vector<int>& a, vector<vector<int>>& e) {
int n=a.size();
for(int i=1;i<=50;i++)c[i].clear();
memset(d,0,sizeof d);
ans=vector<int>(n,0);
for(int i=0;i<n;i++)g[i].clear();
for(auto i:e){
int x=i[0],y=i[1];
g[x].push_back(y);
g[y].push_back(x);
}
dfs(a,0,0);
return ans;
}
};