树上启发式合并
枚举每个数字的所有因子,存起来
官方题解传送门 https://ac.nowcoder.com/discuss/485120?type=101&order=0&pos=2&page=1&channel=-1&source_id=1
题目传送门 https://ac.nowcoder.com/acm/contest/6944/B
具体看代码吧,有注释
#include<cstdio> #include<iostream> #include<algorithm> #include<set> #include<vector> using namespace std; const int maxn = 1e5 + 100; typedef long long ll; vector<int>G[maxn]; void add(int be, int en) { G[be].push_back(en); } int siz[maxn]; int son[maxn]; int dfs(int x, int fa) { siz[x] = 1; int c = 0; for (int p : G[x]) { if (p == fa) continue; dfs(p, x); siz[x] += siz[p]; if (siz[p] > c) { c = siz[p]; son[x] = p; } } return 0; } ll ans[maxn];//最大约数 ll num[maxn];//有num对 ll cnt[maxn];//公共资源,p这个数字是cnt【p】个数字的因子 int list[maxn]; vector<int>ins[maxn]; int cal(int x, int fa, int f) {//计算cnt,f是1就是加,f=-1就是清除答案 for (int p : ins[list[x]]) cnt[p] += f; for (int p : G[x]) { if (p == fa) continue; cal(p, x, f); } return 0; } int cal_ans(int x, int fa,int f,ll &cn,ll &an) {//重儿子算过了,只算轻儿子,cn和an就是cnt[x]和ans[x] for (int p : ins[list[x]]) { if (cnt[p]) { if (p > an) { an = p; cn = cnt[p]; } else if(p == an){ cn += cnt[p]; } } } for (int p : G[x]) { if (p == fa || p == f) continue; cal_ans(p, x, f, cn, an); } return 0; } int dfs2(int x, int fa, int flag) { for (int p : G[x]) { if (p == fa) continue; if (p == son[x]) continue; dfs2(p, x, 0); } if (son[x] != 0) { dfs2(son[x], x, 1); } //num[x] = ans[x] = 0; for (int p : G[x]) { if (p == fa || p == son[x]) continue; cal_ans(p, x, son[x], num[x], ans[x]); cal(p, x, 1); } for (int p : ins[list[x]]) { if (cnt[p]) { if (p > ans[x]) { ans[x] = p; num[x] = cnt[p]; } else if(p == ans[x]){ num[x] += cnt[p]; } } cnt[p]++; } if (flag == 0) { cal(x, fa, -1); } return 0; } int main() { for (int i = 1; i < maxn; i++) { for (int j = 1; j*i < maxn; j++) { ins[i*j].push_back(j);//i*j的所有因子由j组成 } } int n; int x, y; scanf("%d", &n); for (int i = 2; i <= n; i++) { scanf("%d %d", &x, &y); add(x, y); add(y, x); } for (int i = 1; i <= n; i++) { scanf("%d", &list[i]); } dfs(1, -1);//找重儿子 dfs2(1, -1, 0);//启发式合并 for (int i = 1; i <= n; i++) { printf("%lld %lld ", ans[i], num[i]); } return 0; }