版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/imzxww/article/details/82112200
http://acm.hdu.edu.cn/showproblem.php?pid=6430
题意:
一棵树上每个节点权值为v[i],每个节点的heard值是:以它为LCA的两个节点的GCD的最大值,要求输出每个节点的heard值
思路:
因为每个点的权值不超过1e5,所以可以预处理每个点的因子,然后建n颗线段树,只要有两个节点有相同答案就维护答案,每次都把所有子节点的线段树与父节点合并。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int inf=0x7fffffff;
vector<int>v[maxn],yz[maxn];
int root[maxn],ls[maxn*400],rs[maxn*400],sum[maxn*400];
int ans[maxn];
int cnt=0;
void init()
{
for(int i=1;i<maxn;i++)
for(int j=i;j<maxn;j+=i)
yz[j].push_back(i);
}
void update(int k,int l,int r,int &x)
{
if(!x)x=++cnt;
if(l==r)
{
sum[x]=k;
return ;
}
int mid=(l+r)/2;
if(k<=mid)update(k,l,mid,ls[x]);
else update(k,mid+1,r,rs[x]);
sum[x]=max(sum[ls[x]],sum[rs[x]]);
}
int merge(int now,int ch,int &x)
{
if(!now||!ch)return now|ch;
if(sum[now]==sum[ch])x=max(x,sum[now]);
if(ls[now]|ls[ch])ls[now]=merge(ls[now],ls[ch],x);
if(rs[now]|rs[ch])rs[now]=merge(rs[now],rs[ch],x);
return now;
}
void dfs(int u)
{
for(int i=0;i<v[u].size();i++)
{
int k=v[u][i];
dfs(k);
merge(root[u],root[k],ans[u]);
}
}
int main()
{
int n,f;
init();
scanf("%d",&n);
for(int i=1;i<=n;i++)
ans[i]=-1;
for(int i=2;i<=n;i++)
{
scanf("%d",&f);
v[f].push_back(i);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&f);
for(int j=0;j<yz[f].size();j++)
update(yz[f][j],1,1e5,root[i]);
}
dfs(1);
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
return 0;
}