一开始看题目,完全没有思路,想到用dfs,但一直不知道处理。看了别人的思路,最后写了很久,才AC。
大概思路:
对于根节点,要么为0,那么不为0,而且根节点一定处于任意一条路中,利用这个性质,我们可以对根节点的状态进行枚举。
当根节点为0时,那么每条路上的把一个数变成0的机会已经用掉了。那么只有对此时的树进行一次遍历,同时求最大公约数,并记录。
当根节点不为0时,那么每一条路上的最大公约数一定为根节点的约数,因此可以把根节点的约数处理出来,然后再进行一次遍历,对于遍历到的每一个点,用根节点的约数去和它进行处理。如果到当前节点时,每一个约数在这条路径上满足的次数与当前点的深度之差小于1。那么,这个点就可以以这个约数为到该点路径的最大公约数。同时比较,取最大。
注意存边时,要存双向,因为输入并不保证,边是从上到下。
后面就是dfs。

#include <cstdio>
#include <cstring>
#include<vector>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=2e5+5;
int n,ans[N],a[N],d[N];
vector<int>tree[N];
vector<int>gcd;
bool vis[N];
void dfs1(int pos,int g)
{
    vis[pos]=true;
    for(int i=0;i<tree[pos].size();i++)
    {
        int p=tree[pos][i];
        if(vis[p])
            continue;
        if(g>0)
            ans[p]=__gcd(g,a[p]);
        else
            ans[p]=a[p];
        dfs1(p,ans[p]);
    }
}
void dfs2(int pos,int dep)
{
    vis[pos]=true;
    for(int i=0;i<tree[pos].size();i++)
    {
        int p=tree[pos][i];
        if(vis[p])
            continue;
        for(int j=0;j<gcd.size();j++)
        {
            if(a[p]%gcd[j]==0)
                d[j]++;
            if(dep-d[j]<=1)
                ans[p]=max(ans[p],gcd[j]);
        }
        dfs2(p,dep+1);
        for(int j=0;j<gcd.size();j++)
        {
            if(a[p]%gcd[j]==0)
                d[j]--;
        }
    }
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        memset(a,0,sizeof(a));
        memset(ans,0,sizeof(ans));
        memset(d,0,sizeof(d));
        gcd.clear();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            tree[i].clear();
        }
        int x,y;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            tree[x].push_back(y);
            tree[y].push_back(x);
        }
        ans[1]=a[1];
        memset(vis,false,sizeof(vis));
        vis[1]=true;
        dfs1(1,0);
        for(int i=1;i*i<=a[1];i++)//把根节点的所有因子求出
        {
            if(a[1]%i==0)
            {
                gcd.push_back(i);
                if(a[1]/i!=i)
                    gcd.push_back(a[1]/i);
            }
        }
        vis[1]=true;
        memset(vis,false,sizeof(vis));
        dfs2(1,1);
        for(int i=1;i<=n;i++)
        {
            if(i<n)
                printf("%d ",ans[i]);
            else
                printf("%d\n",ans[i]);
        }
    }
    return 0;
}