codeforces 842C 求链上可去掉一个点的最大gcd(思维)

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 ≤ n, 1 ≤ ai ≤ 2·105).

Each of next n - 1 lines contains two integer numbers x and y (1 ≤ x, y ≤ n, x ≠ 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.

Example
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

求每个点到根的可去掉一个点的最大的gcd

第一种做法:把所有的前面所有的gcd都保存下来(就是每个点不要的的情况,用set保存下来)传参方面,传一个新的set,复杂度 n*logmax(a[i])(比这个小)

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5+10;
int a[N];
int an[N];
vector<int> e[N];
void dfs(int x,int y,int gg,set<int> s)
{
    set<int> tt;
    if(!x)
    { 
        an[x]=a[x];
        tt.insert(0);
    }
    else
    {
        an[x]=gg;
        for(set<int>::iterator iter=s.begin();iter!=s.end();iter++)
        {
            tt.insert(__gcd(*iter,a[x]));
        }
        tt.insert(gg);
        gg=__gcd(gg,a[x]);
        an[x]=gg;
        an[x]=max(an[x],*(--tt.end()));
    }
    for(int i=0;i<(int)e[x].size();i++)
    {
        if(e[x][i]==y) continue;
        dfs(e[x][i],x,gg,tt);
    }
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        e[x].push_back(y);
        e[y].push_back(x);
    }
    set<int> ss;
    dfs(1,0,0,ss);
    for(int i=1;i<=n;i++)
        printf("%d ",an[i] );
}

第二种做法,一开始也是想到分解因素,卡壳了,没想到分解因子再回溯,晚上脑子果然不好使 复杂度 On*2sqrt(a[i])

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
int a[N];
vector<int> e[N];
int v[N];
int an[N];
void dfs(int x,int y,int d,int g)
{
    int tt=0;
    for(int i=1;i*i<=a[x];i++)
    {
        if(a[x]%i==0)
        {
            if(i*i==a[x])
            {
                v[i]++;
                if(v[i]>=d)
                tt=max(tt,i);
            }
            else
            {
                v[i]++;
                v[a[x]/i]++;
                if(v[i]>=d) tt=max(tt,i);
                if(v[a[x]/i]>=d) tt=max(tt,a[x]/i);
            }
        }
    }
    tt=max(g,tt);
    g=__gcd(g,a[x]);
    an[x]=tt;
    for(int i=0;i<e[x].size();i++)
    {
        if(e[x][i]==y) continue;
        dfs(e[x][i],x,d+1,g);
    }
    for(int i=1;i*i<=a[x];i++)
    {
        if(a[x]%i==0)
        {
            if(i*i==a[x]) v[i]--;
            else
            {
                v[i]--;
                v[a[x]/i]--;
            }
        }
    }
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(1,0,0,0);
    for(int i=1;i<=n;i++)
        printf("%d ",an[i] );
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 我可以分享一种有效的训练计划,以达到codeforces橙名。首先,建立一个长期的训练计划,每周至少完成3-4个题目,把每个题目的解题过程都认真的思考一遍,确保理解每一步的思路。建议每隔一段时间,做一次综合练习,以更好地检验自己的知识水平。此外,参加竞赛也可以加深对算法的理解,从而提升解题能力。 ### 回答2: 想要在Codeforces达到橙名的水平,需要进行系统性的训练,并掌握一定的算法和编程技巧。以下是一个可能的训练计划: 1. 学习基础知识:首先,建议你系统地学习计算机科学的基础知识,包括数据结构和算法。这可以帮助你理解不同问题的解决方案,并优化代码的执行效率。 2. 解决题目:开始刷题是锻炼算法和编码能力的关键。选择一些简单的题目,如Codeforces的Div2 A、B级题目,按难度逐渐增加。通过不断解决题目,你将熟悉各种算法,并提高编写清晰、高效代码的能力。 3. 学习算法:学习和掌握一些常用算法,如贪心、动态规划、图论等。理解算法原理,分析其时间和空间复杂度,并通过练习将其应用于具体的问题。 4. 参加比赛:参加Codeforces的比赛是衡量自己水平的好方法。开始参加Div2级别的比赛,并争取在中等难度的题目上取得好成绩。逐渐挑战3级、4级比赛,尽量与更强的选手竞争,以提高自己的水平。 5. 反思和学习:每次比赛后,对自己的解题过程进行反思和总结。分析解错的原因,学习其他参赛选手的思考方式和技巧。通过学习他人的优秀代码和解题思路,不断提升自己的编码能力。 6. 练习编码技巧:除了算法,熟练掌握编码技巧也非常重要。学习并应用一些常用的数据结构和STL库,如数组、链表、栈、队列等。多写一些小项目或练习题,锻炼自己的编码能力。 7. 时间管理:合理安排学习和练习的时间。每天保持一定时间的刷题和学习,坚持养成好的学习习惯。同时,在比赛中也要控制好时间,并尽量在限定时间内完成题目。 总之,达到Codeforces橙名的水平需要长期的训练和不断的学习。通过刷题、学习算法和编码技巧、参加比赛以及反思总结,你可以逐渐提升自己的水平,并取得理想的成绩。记住,坚持和持续学习是达到目标的关键。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值