[LOJ]#6159. 「美團 CodeM 初賽 Round A」最長樹鏈 點分治
阿新 • • 發佈:2019-01-08
Description:
Mr. Walker 最近在研究樹,尤其是最長樹鏈問題。現在樹中的每個點都有一個值,他想在樹中找出最長的鏈,使得這條鏈上對應點的值的最大公約數不等於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);
}