题意
给你一棵树,树上的点有权值,对于任意点对(i,j),他们会将gcd(v[i],v[j])告诉LCA,求所有点得到的值得最大值。
题解
由于100000以内的数最多100多个因子,所以我们用线段树记录每个子树包含的因子数。对于当前点u,我们只需要找u节点所有子树包含的公共因子的最大值即可,过程中用线段树合并实现。
AC代码
#include<stdio.h>
#include<vector>
#define N 100005
using namespace std;
vector<int>vt[N],have[N];
int v[N],ans[N],root[N],lchild[N*1600],rchild[N*1600],tree[N*1600],tot;
void build(int L,int R,int root,int x)
{
if(L==R)
{
tree[root]=x;
return ;
}
int mid=L+R>>1;
if(x<=mid)
{
if(!lchild[root])lchild[root]=++tot;
build(L,mid,lchild[root],x);
}
else
{
if(!rchild[root])rchild[root]=++tot;
build(mid+1,R,rchild[root],x);
}
}
int merge(int L,int R,int x,int y,int u)
{
if(!x||!y)return x|y;
if(L==R)
{
ans[u]=max(ans[u],L);
return x;
}
int mid=L+R>>1;
lchild[x]=merge(L,mid,lchild[x],lchild[y],u);
rchild[x]=merge(mid+1,R,rchild[x],rchild[y],u);
return x;
}
void dfs(int u)
{
root[u]=++tot;
for(int i=0;i<have[v[u]].size();i++)
build(1,100000,root[u],have[v[u]][i]);
for(int i=0;i<vt[u].size();i++)
{
int to=vt[u][i];
dfs(to);
root[u]=merge(1,100000,root[u],root[to],u);
}
}
int main()
{
for(int i=1;i<=100000;i++)
for(int j=1;j*j<=i;j++)
if(i%j==0)
{
have[i].push_back(j);
if(j!=i/j)have[i].push_back(i/j);
}
int n;
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
int fa;
scanf("%d",&fa);
vt[fa].push_back(i);
}
for(int i=1;i<=n;i++)
scanf("%d",&v[i]);
dfs(1);
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]==0?-1:ans[i]);
}