【bzoj 十连测】[noip2016十连测第五场]Problem B: walk(dfs求最长链)
【题解】【DFS+最长链】
【按gcd重新构图,每次选定一个gcd,把所有加入后gcd仍为选定值的边加入树中,dfs求最长路】
【记录每个最长链的gcd。最后从后往前枚举长度,更新每个长度的gcd为最大值(ans[i]=max(ans[i],ans[i+1]))】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
int s,t,nxt;
}mp[400010],a[800010];
int point[1000010],p[400010],link[800010],len[800010];
int ans[400010],maxlen,num,maxn;
int n,tot,cnt;
inline void Add(int x,int y,int val)
{
tot++; mp[tot].s=x; mp[tot].t=y;
mp[tot].nxt=point[val]; point[val]=tot;
}
inline void add(int x,int y)
{
cnt++; a[cnt].s=x; a[cnt].t=y;
a[cnt].nxt=p[x]; p[x]=cnt; link[cnt]=x;
cnt++; a[cnt].s=y; a[cnt].t=x;
a[cnt].nxt=p[y]; p[y]=cnt; link[cnt]=y;
}
int dfs(int x)
{
len[x]=num;
int maxson=0;
for(int i=p[x];i;i=a[i].nxt)
if(len[a[i].t]!=num)
{
int b=dfs(a[i].t);
maxlen=max(maxlen,maxson+b+1);
maxson=max(maxson,b+1);
}
return maxson;
}
int main()
{
//freopen("walk.in","r",stdin);
//freopen("walk.out","w",stdout);
int i,j;
scanf("%d",&n);
for(i=1;i<n;++i)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
Add(x,y,z); maxn=max(maxn,z);
}
for(int k=1;k<=maxn;++k)
{
for(i=k;i<=maxn;i+=k)
for(j=point[i];j;j=mp[j].nxt)
add(mp[j].s,mp[j].t);
maxlen=0; num++;
for(i=1;i<=cnt;++i)
if(len[link[i]]!=num) dfs(link[i]);
for(i=1;i<=cnt;++i) p[link[i]]=0;
cnt=0; ans[maxlen]=k;
}
for(i=n-1;i>0;--i) ans[i]=max(ans[i],ans[i+1]);
for(i=1;i<=n;++i) printf("%d\n",ans[i]);
return 0;
}
既然无能更改,又何必枉自寻烦忧