Codeforces Round #430(Div.2)Problem C Ilya And The Tree(DFS)

C. Ilya And The Tree
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Ilya is very fond of graphs, especially trees. During his last trip to the forest Ilya found a very interesting tree rooted at vertex 1. There is an integer number written on each vertex of the tree; the number written on vertex i is equal to ai.

Ilya believes that the beauty of the vertex x is the greatest common divisor of all numbers written on the vertices on the path from the root to x, including this vertex itself. In addition, Ilya can change the number in one arbitrary vertex to 0 or leave all vertices unchanged. Now for each vertex Ilya wants to know the maximum possible beauty it can have.

For each vertex the answer must be considered independently.

The beauty of the root equals to number written on it.

Input

First line contains one integer number n — the number of vertices in tree (1 ≤ n ≤ 2·105).

Next line contains n integer numbers ai (1 ≤ i ≤ n1 ≤ ai ≤ 2·105).

Each of next n - 1 lines contains two integer numbers x and y (1 ≤ x, y ≤ nx ≠ y), which means that there is an edge (x, y) in the tree.

Output

Output n numbers separated by spaces, where i-th number equals to maximum possible beauty of vertex i.

Examples
input
2
6 2
1 2
output
6 6 
input
3
6 2 3
1 2
1 3
output
6 6 6 
input
1
10
output
10 

【思路】
这道题第一直觉就是深搜,当时打一半被hack了A题(本场大家的A题可以说是非常惨了),心里有些慌,写了挺长时间才写完,但是在第6个点TLE了,在剩下的时间内也没想到如何剪枝和记忆化优化,所以没做出来。第二天起床加了一个剪枝就过了,实在令人遗憾。大体思路就是从根节点往下深搜,每到一个点就检验置零的机会是否用完,传参时传递一个bool型就好,true为用了,false为还没用。如果还没用,那么该点可以选择用,也可以选择不用,有两条路可走;如果已经用了,那么以后就不能用了,只有一条路可走。剪枝的情况就在于,如果到某一个节点置零机会还未用,且这个节点与前面的所有节点的gcd刚好等于前面所有节点的gcd,那么只需要走一条路,不必用掉这次机会,因为该节点置零以后求gcd依旧是前面所有节点的gcd,而要得到所有点的beauty就要尽可能保留这次机会,所以可以在此处剪枝。

【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXN=200005;

struct edge{
    int to,next;
};

int n,cnt;
int a[MAXN],head[MAXN],ans[MAXN];
edge e[MAXN*2];

void addedge(int from,int to)
{
    cnt++;
    e[cnt].to=to;
    e[cnt].next=head[from];
    head[from]=cnt;
}

int gcd(int a,int b)
{
    return (b==0?a:gcd(b,a%b));
}

void dfs(int fa,int u,int d,bool mes)
{
    int p,q;
    p=gcd(d,a[u]);
    ans[u]=max(ans[u],p);
    if(!mes){
        q=gcd(d,0);
        ans[u]=max(ans[u],q);
    }
    for(int i=head[u];i>0;i=e[i].next){
        int v=e[i].to;
        if(v==fa)continue;
        if(!mes){
            dfs(u,v,p,false);
            if(p!=d)dfs(u,v,q,true);
        }
        else
            dfs(u,v,p,true);
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    cnt=0;
    for(int i=1;i<=n-1;i++){
        int a,b;
        scanf("%d %d",&a,&b);
        addedge(a,b);
        addedge(b,a);
    }
    memset(ans,0,sizeof(ans));
    dfs(0,1,0,false);
    for(int i=1;i<=n;i++)
        printf("%d ",ans[i]);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值