[HDU 6430] Problem E. TeaTree

前言:

复健后的第一题,写了1.5H你敢信?

题目链接:

HDU 6430

题意描述:

给出一个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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值