思路:
1. 如果根节点是0,那么可以通过一次dfs计算出所有节点的最大值。
2. 如果根节点不是0,那么其余各点的最大值一定是根节点的一个因子。首先计算出根节点的所有因子。在dfs到一个深度为d的节点v时,遍历所有因子:对于因子x,p表示从根节点到达v的路径中能够被x整除的节点个数。如果p >= d - 1,则x就是当前节点的一个候选最大值(d-1是因为可以把路径中其中一个数替换为0)。
于是通过两次dfs即可得出答案。复杂度O(n * sqrt(n))。在dfs的过程中,要注意维护全局变量。dfs到下一个分支时,要把上一个分支对全局变量造成的影响消除。
实现:
1 #include <bits/stdc++.h> 2 using namespace std; 3 int a[200005], val[200005]; 4 vector<int> tree[200005]; 5 int vis[200005]; 6 int divisors[1005]; 7 8 void dfs(int cur, int div) 9 { 10 vis[cur] = 1; 11 for (int i = 0; i < tree[cur].size(); i++) 12 { 13 int tmp = tree[cur][i]; 14 if (vis[tmp]) continue; 15 val[tmp] = __gcd(div, a[tmp]); 16 dfs(tmp, val[tmp]); 17 } 18 } 19 20 void dfs2(int cur, int d, vector<int>& v) 21 { 22 vis[cur] = 1; 23 for (int i = 0; i < tree[cur].size(); i++) 24 { 25 int tmp = tree[cur][i]; 26 if (vis[tmp]) continue; 27 for (int j = 0; j < v.size(); j++) 28 { 29 if (a[tmp] % v[j] == 0) divisors[j]++; 30 if (divisors[j] >= d) val[tmp] = max(val[tmp], v[j]); 31 } 32 dfs2(tmp, d + 1, v); 33 for (int j = 0; j < v.size(); j++) 34 if (a[tmp] % v[j] == 0) divisors[j]--; 35 } 36 } 37 38 int main() 39 { 40 int n, x, y; 41 while (cin >> n) 42 { 43 for (int i = 1; i <= n; i++) 44 tree[i].clear(); 45 for (int i = 1; i <= n; i++) 46 cin >> a[i]; 47 for (int i = 0; i < n - 1; i++) 48 { 49 cin >> x >> y; 50 tree[x].push_back(y); 51 tree[y].push_back(x); 52 } 53 int tmp = a[1]; 54 a[1] = 0; 55 memset(vis, 0, sizeof vis); 56 dfs(1, 0); 57 a[1] = val[1] = tmp; 58 vector<int> v; 59 for (int i = 1; i * i <= a[1]; i++) 60 { 61 if (a[1] % i == 0) 62 { 63 v.push_back(i); 64 if (a[1] / i != i) v.push_back(a[1] / i); 65 } 66 } 67 sort(v.begin(), v.end()); 68 for (int i = 0; i < v.size(); i++) divisors[i] = 1; 69 memset(vis, 0, sizeof vis); 70 dfs2(1, 1, v); 71 for (int i = 1; i <= n; i++) 72 cout << val[i] << " "; 73 cout << endl; 74 } 75 return 0; 76 }