Description
有一颗树,每个点有一个点权,边权都是 (1),问路径上的所有点的 gcd 不是 (1) 的最长路径是多少?
Solution
分治到每个点时,考虑当前分治范围内经过该点的路径。
对于每个子树,记录一个映射,表示每个数能到达的最深的深度,边搜索边更新即可。
维护当前分治主树的映射,枚举完一个子树后,用子树映射和主树映射中的值更新答案,并将子树映射并入主树映射中。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define foradj(p) for(pair<int,int> pr:g[p])
#define unpii(q,w) int q=pr.first, w=pr.second;
const int N = 200005;
vector <pair<int,int> > g[N];
int dis[N],siz[N],n,m,t1,t2,t3,k[N],vis[N],sum,rt,rtval,val[N],ans;
vector<int> st,wl;
set<int> s;
map<int,int> mp_main,mp_sub;
void findroot(int p,int ff)
{
siz[p]=1;
int mx=0;
foradj(p)
{
unpii(q,w);
if(!vis[q] && q!=ff)
{
findroot(q,p);
siz[p]+=siz[q];
mx=max(mx,siz[q]);
}
}
mx=max(mx,sum-siz[p]);
if(mx<rtval) rtval=mx, rt=p;
}
void dfs(int p,int ff,int x)
{
if(x==1) return;
mp_sub[x]=max(mp_sub[x],dis[p]);
foradj(p)
{
unpii(q,w);
if(!vis[q] && q!=ff)
{
dis[q]=dis[p]+1;
dfs(q,p,__gcd(x,val[q]));
}
}
}
void solve(int p)
{
vis[p]=1;
mp_main.clear();
mp_main[val[p]]=0;
foradj(p)
{
unpii(q,w);
if(!vis[q])
{
dis[q]=1;
dfs(q,p,__gcd(val[p],val[q]));
/*cout<<"q="<<q<<" p="<<p<<endl;
cout<<"sub: ";
for(auto i:mp_sub) cout<<i.first<<" ";
cout<<endl;
cout<<"main:";
for(auto i:mp_main) cout<<i.first<<" ";
cout<<endl;*/
for(auto i:mp_main)
{
for(auto j:mp_sub)
{
if(__gcd(i.first,j.first)>1)
{
//cout<<i.first<<" "<<j.first<<endl;
ans=max(ans,i.second+j.second+1);
}
}
}
for(auto i:mp_sub)
{
mp_main[i.first]=max(mp_main[i.first],i.second);
}
mp_sub.clear();
}
}
foradj(p)
{
unpii(q,w);
if(!vis[q])
{
sum=siz[q];
rtval=1e18;
findroot(q,0);
solve(rt);
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>val[i];
}
for(int i=1;i<n;i++)
{
cin>>t1>>t2;
g[t1].push_back({t2,1});
g[t2].push_back({t1,1});
}
sum=n;
rtval=1e18;
findroot(1,0);
solve(rt);
for(int i=1;i<=n;i++) if(val[i]>1) ans=max(ans,1ll);
cout<<ans<<endl;
}