Description:
Mr. Walker 最近在研究树,尤其是最长树链问题。现在树中的每个点都有一个值,他想在树中找出最长的链,使得这条链上对应点的值的最大公约数不等于1。请求出这条最长的树链的长度。
题解:
我的做法大概是最差的……不过是我自己想的。
点分治,对于每个重心找经过它的路径答案,设
f
i
f_i
fi表示最大公约数为
i
i
i倍数的最大深度,由于每个数不同的质因数不会超过
10
10
10个,所以每到一个点可以暴力更新它所含有的质因数的
f
f
f,这样复杂度是
O
(
10
n
log
n
)
O(10n\log n)
O(10nlogn)。
正解是枚举质因数,然后把含有该质因数的点设为
1
1
1后找树的直径,由于每个点只会在枚举到它的质因数时被访问一次,所以复杂度为所有数的质因数个数和,十分优秀,可惜我没有想到。
一开始TLE的怀疑人生……一度想去膜题解,还好最后发现是点分治打错了,不要轻易放弃。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=100010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,a[Maxn],ans=1;
unordered_map<int,int> f;
int gcd(int a,int b)
{
if(!a)return b;
return gcd(b%a,a);
}
vector<int>p[Maxn],pp[Maxn];
vector<pa>tmp;
struct Edge{int y,next;}e[Maxn<<1];
int last[Maxn],len=0;
void ins(int x,int y)
{
int t=++len;
e[t].y=y;e[t].next=last[x];last[x]=t;
}
int prime[4000],lp=0;bool mark[32000];
void pre()
{
for(int i=2;i<31622;i++)
{
if(!mark[i])prime[++lp]=i;
for(int j=1;prime[j]*i<31622&&j<=lp;j++)
{
mark[prime[j]*i]=true;
if(i%prime[j]==0)break;
}
}
}
bool vis[Maxn];int root=0,son[Maxn],tot;
int get_root(int x,int fa)
{
int sz=1,mx=0;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(y==fa||vis[y])continue;
int t=get_root(y,x);
sz+=t;mx=max(mx,t);
}
son[x]=max(mx,tot-sz);
if(son[x]<son[root])root=x;
return sz;
}
int get_size(int x,int fa)
{
int sz=1;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(y==fa||vis[y])continue;
sz+=get_size(y,x);
}
return sz;
}
void DFS(int v,int x,int fa,int op,int dep)
{
if(op==1)
{
tmp.push_back(make_pair(x,dep));
for(int i=0;i<pp[x].size();i++)
ans=max(ans,dep+1+f[pp[x][i]]);
}
else
{
for(int i=0;i<pp[x].size();i++)
f[pp[x][i]]=0;
}
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(y==fa||vis[y])continue;
int t=gcd(a[x],a[y]);
if(t==1)continue;
pp[y].clear();
if(pp[x].size()<p[y].size())
{
for(int j=0;j<pp[x].size();j++)
if(t%pp[x][j]==0)pp[y].push_back(pp[x][j]);
}
else
{
for(int j=0;j<p[y].size();j++)
if(t%p[y][j]==0)pp[y].push_back(p[y][j]);
}
DFS(t,y,x,op,dep+1);
}
}
void work(int x,int op)
{
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(vis[y])continue;
int t=gcd(a[x],a[y]);
if(t==1)continue;
pp[y].clear();tmp.clear();
if(p[x].size()<p[y].size())
{
for(int j=0;j<p[x].size();j++)
if(t%p[x][j]==0)pp[y].push_back(p[x][j]);
}
else
{
for(int j=0;j<p[y].size();j++)
if(t%p[y][j]==0)pp[y].push_back(p[y][j]);
}
DFS(t,y,x,op,1);
for(int j=0;j<tmp.size();j++)
for(int k=0;k<pp[tmp[j].first].size();k++)
f[pp[tmp[j].first][k]]=max(f[pp[tmp[j].first][k]],tmp[j].second);
}
}
void dfs(int x)
{
vis[x]=true;
work(x,1);work(x,-1);
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(vis[y])continue;
tot=get_size(y,x);
if(tot<=ans)continue;
root=0;get_root(y,x);dfs(root);
}
}
int main()
{
pre();son[0]=inf;
n=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
ins(x,y),ins(y,x);
}
for(int i=1;i<=n;i++)
{
int x=read();
a[i]=x;
for(int j=1;prime[j]*prime[j]<=a[i]&&j<=lp;j++)
if(x%prime[j]==0)
{
p[i].push_back(prime[j]);
while(x%prime[j]==0)x/=prime[j];
}
if(x!=1)p[i].push_back(x);
}
tot=n;get_root(1,0);dfs(root);
printf("%d",ans);
}