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; }