CodeForces - 1101D GCD Counting【树的直径】

D. GCD Counting

time limit per test

4.5 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

You are given a tree consisting of nn vertices. A number is written on each vertex; the number on vertex ii is equal to aiai.

Let's denote the function g(x,y)g(x,y) as the greatest common divisor of the numbers written on the vertices belonging to the simple path from vertex xx to vertex yy (including these two vertices). Also let's denote dist(x,y)dist(x,y) as the number of vertices on the simple path between vertices xx and yy, including the endpoints. dist(x,x)=1dist(x,x)=1 for every vertex xx.

Your task is calculate the maximum value of dist(x,y)dist(x,y) among such pairs of vertices that g(x,y)>1g(x,y)>1.

Input

The first line contains one integer nn — the number of vertices (1≤n≤2⋅105)(1≤n≤2⋅105).

The second line contains nn integers a1a1, a2a2, ..., anan (1≤ai≤2⋅105)(1≤ai≤2⋅105) — the numbers written on vertices.

Then n−1n−1 lines follow, each containing two integers xx and yy (1≤x,y≤n,x≠y)(1≤x,y≤n,x≠y) denoting an edge connecting vertex xx with vertex yy. It is guaranteed that these edges form a tree.

Output

If there is no pair of vertices x,yx,y such that g(x,y)>1g(x,y)>1, print 00. Otherwise print the maximum value of dist(x,y)dist(x,y) among such pairs.

 

 

因为一条链上的所有数的gcd>1,即可以理解为他们有相同的质因子,那么只需要取枚举每个质数,跑一个树的直径即可。

线性筛出1到2e5的数的所有质因子,然后找出每个质数所对应的点,枚举然后跑dfs。

#include "bits/stdc++.h"
using namespace std;
int a[200004];
vector<int>isp;//质数
set<int>prim[200004];//每个数的质因子
vector<int>xxx[200004];//每个质数对应的点
bool vis[200004];
bool vs[200004];
struct edge
{
    int v,nxt;
}g[400004];
int head[400004];
int cnt;
int n;
void addedge(int u,int v)
{
    g[cnt].v=v;
    g[cnt].nxt=head[u];
    head[u]=cnt;
    ++cnt;
}
int ans=0;
int tu;
void dfs(int u,int pre,int gc,int num,int ok)
{
    if(!ok&&vs[u])return ;
    vs[u]=1;
    for (int i = head[u]; i !=-1 ; i=g[i].nxt) {
        int v=g[i].v;
        if(v!=pre&&(prim[a[v]].find(gc)!=prim[a[v]].end()))
            dfs(v,u,gc,num+1,ok);
    }
    if(num>ans)
    {
        ans=num;
        tu=u;
    }
}
int main()
{
    cin>>n;
    cnt=0;
    memset(head,-1, sizeof(head));
    memset(vis,0, sizeof(vis));
    memset(vs,0, sizeof(vs));
    for (int i = 2; i <= 200000 ; ++i) {//筛
        if(!vis[i]) {
            isp.push_back(i);
            for (int j = i ; j <= 200000; j += i) {
                if(j!=i)vis[j] = 1;
                prim[j].insert(i);
            }
        }
    }
    int ok=0;
    int maxn=0;
    for (int i = 1; i <= n; ++i) {
        scanf("%d",&a[i]);
        for (auto j = prim[a[i]].begin(); j != prim[a[i]].end(); ++j) {//维护质数对应的点
            xxx[*j].push_back(i);
            maxn=max(maxn,*j);
        }
        if(a[i]!=1)ok=1;

    }
    for (int i = 0; i < n-1; ++i) {
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);
        addedge(y,x);
    }

    int ANS=0;
    for (int i = 2; i <= maxn; ++i) {//枚举质数
        if(!vis[i])
        {
            memset(vs,0, sizeof(vs));
            for (int j = 0; j < xxx[i].size(); ++j) {//每个点都要跑,因为有相同质因子的数可能不在一条链上
                ans=0;
                int xxxx=tu;
                dfs(xxx[i][j],-1,i,1,0);
                if(xxxx!=tu){
                    dfs(tu,-1,i,1,1);
                    ANS=max(ANS,ans);
                }

            }
        }
    }
    if(ok)
    printf("%d\n",ANS);
    else puts("0");
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值