HDU 6430 Problem E. TeaTree [线段树合并]

题意

给你一棵树,树上的点有权值,对于任意点对(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]);
}

猜你喜欢

转载自blog.csdn.net/ACTerminate/article/details/81948995