hdu 6430 Problem E. TeaTree (合并线段树)

版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}

猜你喜欢

转载自blog.csdn.net/imzxww/article/details/82112200