前言:
复健后的第一题,写了1.5H你敢信?
题目链接:
题意描述:
给出一个N个节点的树,每个树的节点都有一个权值val[i].
对于一个节点 X Ans[X]=max(gcd[val[i],val[j]]) (LCA(i,j)==X)
现在让你求出每个节点的Ans值
题目分析:
很明显,对于每个节点的Ans值,我们只需要求在它的子节点子树里出现的出现两次的因数中最大的就好了,我们只需要对整个树DFS一遍,用权值线段树维护每个节点子树因数出现的情况,用线段树合并,在合并的过程中即可统计答案。
代码实现:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
const int MAXN=1e5+10;
int Maxs=-1;
int tag[MAXN*400],root[MAXN*400],ls[MAXN*400],rs[MAXN*400];
int val[MAXN];
int n,sz;
int head[MAXN],net[MAXN],to[MAXN],cnt;
int Ans[MAXN];
vector<int> num[MAXN];
void add(int u,int v)
{
cnt++;
to[cnt]=v,net[cnt]=head[u],head[u]=cnt;
}
void insert(int &now,int l,int r,int ind)
{
if(!now) now=++sz;
if(l>=r) {tag[now]=ind;return;}
int mid=(l+r)>>1;
ind<=mid?insert(ls[now],l,mid,ind):insert(rs[now],mid+1,r,ind);
tag[now]=max(tag[ls[now]],tag[rs[now]]);
}
int merge(int x,int y,int &ans)
{
if(!x||!y) return x|y;
if(tag[x]==tag[y]) ans=max(ans,tag[x]);
ls[x]=merge(ls[x],ls[y],ans);
rs[x]=merge(rs[x],rs[y],ans);
return x;
}
void dfs(int x)
{
for(int i=head[x];i;i=net[i])
{
dfs(to[i]);
merge(root[x],root[to[i]],Ans[x]);
}
}
void pre()
{
for(int i=1;i<=1e5;i++)
{
int l=sqrt(i);
for(int j=1;j<=l;j++)
if(i%j==0)
{
num[i].push_back(j);
if(j<i/j) num[i].push_back(i/j);
}
}
}
int main()
{
pre();
scanf("%d",&n);
for(int i=2,x;i<=n;i++)
{
scanf("%d",&x);
add(x,i);
}
for(int i=1;i<=n;i++) scanf("%d",&val[i]),Maxs=std::max(Maxs,val[i]),Ans[i]=-1;
for(int i=1;i<=n;i++) for(int j=0;j<num[val[i]].size();j++) insert(root[i],1,Maxs,num[val[i]][j]);
dfs(1);
for(int i=1;i<=n;i++) printf("%d\n",Ans[i]);
return 0;
}