题目描述
分析
一条边只会在枚举它因子作为答案时才有用
所以,我们考虑从 (1) 到最大值枚举答案 (w),把所有倍数是 (w) 的边连起来
在形成的森林中跑一个直径
这样相当于把每条边分成因子个数条边
注意,你不能一开始就建好图然后在枚举时打标记,这样你走的边会变多
时间复杂度 (O(n imes sqrt{n}))
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<ctime>
#define rg register
inline int read(){
rg int x=0,fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=1e6+5;
int n,h[maxn],tot=1,mmax;
struct asd{
int to,nxt;
}b[maxn];
struct jie{
int zb,yb;
jie(){}
jie(int aa,int bb){
zb=aa,yb=bb;
}
};
void ad(int aa,int bb){
b[tot].to=bb;
b[tot].nxt=h[aa];
h[aa]=tot++;
}
std::vector<jie> g[maxn];
int ans[maxn],dis[maxn],sta[maxn],tp,vis[maxn],tim,maxdis,jl,jll;
void dfs(int now,int fa){
vis[now]=tim;
for(rg int i=h[now];i!=-1;i=b[i].nxt){
rg int u=b[i].to;
if(u==fa) continue;
dis[u]=dis[now]+1;
if(dis[u]>maxdis){
maxdis=dis[u];
jl=u;
}
dfs(u,now);
}
}
int main(){
freopen("walk.in","r",stdin);
freopen("walk.out","w",stdout);
memset(h,-1,sizeof(h));
n=read();
rg int aa,bb,cc;
for(rg int i=1;i<n;i++){
aa=read(),bb=read(),cc=read();
g[cc].push_back(jie(aa,bb));
if(cc>mmax) mmax=cc;
}
for(rg int i=1;i<=mmax;i++){
tp=0;
tot=1;
tim++;
for(rg int j=i;j<=mmax;j+=i){
for(rg int k=0;k<g[j].size();k++){
sta[++tp]=g[j][k].zb;
sta[++tp]=g[j][k].yb;
ad(g[j][k].zb,g[j][k].yb);
ad(g[j][k].yb,g[j][k].zb);
}
}
for(rg int j=1;j<=tp;j++){
if(vis[sta[j]]!=tim){
maxdis=0,jl=0;
dis[sta[j]]=0;
dfs(sta[j],0);
jll=jl;
maxdis=0,jl=0;
dis[jll]=0;
dfs(jll,0);
ans[maxdis]=i;
}
}
for(rg int j=1;j<=tp;j++){
h[sta[j]]=-1;
}
}
for(rg int i=n;i>=1;i--){
ans[i]=std::max(ans[i],ans[i+1]);
}
for(rg int i=1;i<=n;i++){
printf("%d
",ans[i]);
}
return 0;
}