【LOJ6159】「美团 CodeM 初赛 Round A」最长树链(树的直径)
大致题意: 给定一棵树,每个点有一个点权,求最长链满足链上所有点权\(gcd\not=1\)。
套路
首先,看到\(gcd\),我们可以进行一个套路转化:
枚举一个质因子,每次只保留点权是这个质因子倍数的点,然后\(BFS\)求树的直径。
于是这道题就做完了。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define LN 15
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
using namespace std;
int n,ans,tg[N+5],vis[N+5],ee,lnk[N+5];struct edge {int to,nxt;}e[2*N+5];
int cnt;map<int,int> p;vector<int> v[N*LN+5];
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define D isdigit(c=tc())
char c,*A,*B,FI[FS];
public:
I FastIO() {A=B=FI;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
}F;
int Pt,P[N+5];I void Sieve()//线性筛预处理,筛质数
{
RI i,j;for(i=2;i<=N;++i) for(!P[i]&&(P[++Pt]=i),
j=1;j<=Pt&&1LL*i*P[j]<=N;++j) if(P[i*P[j]]=1,!(i%P[j])) break;
}
I void Resolve(CI id,RI x)//分解x
{
#define Pos(x) (p[x]?p[x]:(p[x]=++cnt))
for(RI i=1;i<=Pt&&1LL*P[i]*P[i]<=x;++i) if(!(x%P[i])) {v[Pos(P[i])].push_back(id);W(!(x%P[i])) x/=P[i];}
x^1&&(v[Pos(x)].push_back(id),0);
}
int q[N+5],g[N+5],dis[N+5];I int BFS(CI p,CI x)//BFS
{
static int ti=0;RI i,k,f=0,H=1,T=1;q[1]=x,g[x]=++ti,dis[x]=0;
W(H<=T) for(i=lnk[k=q[H++]];i;i=e[i].nxt) g[e[i].to]^ti&&tg[e[i].to]==p&&
(vis[e[i].to]=p,g[e[i].to]=ti,(dis[e[i].to]=dis[k]+1)>dis[f]&&(f=e[i].to),q[++T]=e[i].to);
return f;
}
I void TD(CI p,RI x) {x=BFS(p,x),x=BFS(p,x),ans=max(ans,dis[x]+1);}//树的直径
int main()
{
RI i,x,y;for(Sieve(),F.read(n),i=1;i^n;++i) F.read(x),F.read(y),add(x,y),add(y,x);
RI j,s;for(i=1;i<=n;++i) F.read(x),Resolve(i,x);for(i=1;i<=cnt;++i)//枚举质因子
{
for(s=v[i].size(),j=0;j^s;++j) tg[v[i][j]]=i;//给包含这个质因子的数打上标记
for(j=0;j^s;++j) vis[x=v[i][j]]^i&&(TD(i,x),0);//求树的直径
}return printf("%d\n",ans),0;
}
待到再迷茫时回头望,所有脚印会发出光芒