分析

这不是 的模板题。先对于每个节点的值分解为所有因数。然后处理一个节点时,先处理轻儿子,取消其贡献。再处理重儿子保留贡献。最后暴力加上轻子树。因为一个点到根节点只有 条轻路径,所以子树也只会被暴力加 次。总的时间复杂度为

代码

#include<bits/stdc++.h>
using namespace std;
int read() {
    int x = 0,f = 0;char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-')f = 1;ch = getchar();}
    while(isdigit(ch)) {x = x * 10 + ch - '0' ;ch = getchar();}
    return f?-x:x;
}
const int N = 110000;
vector<int> h[N],G[N];
int n,L[N],R[N],id[N],Id,si[N],son[N];
int ans[N],cnt[N],C[N],Ans,Cnt;
void dfs(int x,int fa) {
    si[x] = 1;id[L[x] = ++Id] = x;
    for(auto y:G[x]) {
        if(y == fa) continue;
        dfs(y,x);si[x] += si[y];
        if(si[son[x]] < si[y]) son[x] = y; 
    }R[x] = Id;
}
void work(int x) {
    for(auto z:h[x]) {
        if(C[z]) {
            if(z > Ans) Ans = z,Cnt = C[z];
            else if(z == Ans) Cnt += C[z];
        }
    }
}
void calc(int x) {
    for(int i = L[x];i <= R[x];i++) work(id[i]);
}
void solve(int x,int fa,int keep) {
    for(auto y:G[x]) {
        if(y == son[x] || y == fa) continue;solve(y,x,0);
    } 
    if(son[x]) solve(son[x],x,1);
    Ans = 0;Cnt = 0;
    for(auto y:G[x]) {
        if(y == son[x] || y == fa) continue;
        calc(y);
        for(int i = L[y];i <= R[y];i++) {
            for(auto z:h[id[i]]) C[z]++;
        }
    }
    work(x);
    ans[x] = Ans;cnt[x] = Cnt;
    for(auto z:h[x]) C[z]++;
    if(keep) return;
    memset(C,0,sizeof(C));  
}
int main()
{
    n = read();
    for(int i = 1;i < n;i++) {
        int x = read(),y = read();
        G[x].push_back(y);G[y].push_back(x);
    }
    for(int i = 1;i <= n;i++) {
        int val = read();
        for(int j = 1;j * j <= val;j++) {
            if((val%j)) continue;
            h[i].push_back(j);
            if(j * j != val) h[i].push_back(val/j);
        }
    }
    dfs(1,0);
    solve(1,0,0);
    for(int i = 1;i <= n;i++) {
        printf("%d %d\n",ans[i],cnt[i]);
    }
    return 0;
}