CF1101D GCD Counting 点分治+质因数分解

题意:求最长的树上路径点值的 $gcd$ 不为 $1$ 的长度.
由于只要求 $gcd$ 不为一,所以只要 $gcd$ 是一个大于等于 $2$ 的质数的倍数就可以了.
而我们发现 $2\times 10^5$ 以内的数最多只会有 $7$~$8$ 个本质不同的质因子,所以我们在点分治的时候暴力拆质因子并维护一些桶即可.

#include <cstdio> 
#include <vector> 
#include <algorithm> 
#define N 200004  
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
int n,tot,edges,sn,root,tl,answer; 
vector<int>v[N];   
int prime[N],is[N],num[N]; 
int val[N],hd[N],to[N<<1],nex[N<<1];       
int size[N],mx[N],vis[N],f[N],g[N],tmp[N],depth[N],cur[N],number[N];          
void add(int u,int v) 
{
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;    
}     
void getroot(int u,int ff) 
{
    size[u]=1,mx[u]=0; 
    for(int i=hd[u];i;i=nex[i]) 
        if(to[i]!=ff&&!vis[to[i]]) 
            getroot(to[i],u),size[u]+=size[to[i]],mx[u]=max(mx[u],size[to[i]]); 
    mx[u]=max(mx[u],sn-size[u]); 
    if(mx[u]<mx[root]) root=u;    
}   
void dfs(int u,int ff,int dep) 
{    
    number[u]=tmp[++tl]=__gcd(val[u],number[ff]),depth[tl]=dep;       
    for(int i=hd[u];i;i=nex[i]) 
        if(to[i]!=ff&&!vis[to[i]])      
            dfs(to[i],u,dep+1);     
}
void calc(int u) 
{   
    int i,j,re;      
    if(val[u]>1) answer=max(answer,1);  
    tl=0;      
    number[u]=val[u];   
    for(i=hd[u];i;i=nex[i]) 
    {
        if(vis[to[i]]) continue;    
        re=tl+1,dfs(to[i],u,1);     
        for(j=re;j<=tl;++j) 
        {
            int a=tmp[j],b=depth[j];  
            if(a>1) 
            { 
                for(int k=0;k<v[a].size();++k) 
                    g[v[a][k]]=max(g[v[a][k]],b),answer=max(answer,g[v[a][k]]+f[v[a][k]]+1);    
            }
        }          
        for(j=re;j<=tl;++j) 
        {
            int a=tmp[j];       
            if(a>1) 
            {
                for(int k=0;k<v[a].size();++k) f[v[a][k]]=max(f[v[a][k]],g[v[a][k]]);    
            }
        }      
        for(j=re;j<=tl;++j) 
        {
            int a=tmp[j]; 
            if(a>1) for(int k=0;k<v[a].size();++k) g[v[a][k]]=0; 
        }
    } 
    for(i=1;i<=tl;++i) 
    {
        int a=tmp[i]; 
        if(a>1) for(j=0;j<v[a].size();++j) f[v[a][j]]=g[v[a][j]]=0;   
    }
}
void solve(int u) 
{ 
    vis[u]=1,calc(u);    
    for(int i=hd[u];i;i=nex[i]) 
        if(!vis[to[i]]) 
            sn=size[to[i]],root=0,getroot(to[i],u),solve(root);
}
void init() 
{ 
    int i,j;  
    for(i=2;i<N;++i) 
    {
        if(!is[i]) prime[++tot]=i;            
        for(j=1;j<=tot&&i*prime[j]<N;++j) 
        {
            is[i*prime[j]]=1;            
            if(i%prime[j]==0) break;       
        }  
    }    
    for(i=2;i<N;++i) num[i]=i; 
    for(i=1;i<=tot;++i) 
        for(j=prime[i];j<N;j+=prime[i])   
        { 
            v[j].push_back(prime[i]);    
            while(num[j]%prime[i]==0) num[j]/=prime[i];   
        }
}
int main() 
{
    int i,j;    
    init();    
    // setIO("input");  
    scanf("%d",&n); 
    for(i=1;i<=n;++i) scanf("%d",&val[i]); 
    for(i=1;i<n;++i) 
    {
        int a,b; 
        scanf("%d%d",&a,&b),add(a,b),add(b,a);   
    }   
    mx[root=0]=sn=n,getroot(1,0),solve(root);
    printf("%d\n",answer);       
    return 0;    
}         

  

posted @ 2019-09-06 18:05  EM-LGH  阅读(205)  评论(0编辑  收藏  举报