HDU 6430 TeaTree (线段树合并)

Problem E. TeaTree

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 1248    Accepted Submission(s): 478


Problem Description
Recently, TeaTree acquire new knoledge gcd (Greatest Common Divisor), now she want to test you.
As we know, TeaTree is a tree and her root is node 1, she have n nodes and n-1 edge, for each node i, it has it’s value v[i].
For every two nodes i and j (i is not equal to j), they will tell their Lowest Common Ancestors (LCA) a number : gcd(v[i],v[j]).
For each node, you have to calculate the max number that it heard. some definition:
In graph theory and computer science, the lowest common ancestor (LCA) of two nodes u and v in a tree is the lowest (deepest) node that has both u and v as descendants, where we define each node to be a descendant of itself.
 

 

Input
On the first line, there is a positive integer n, which describe the number of nodes.
Next line there are n-1 positive integers f[2] ,f[3], …, f[n], f[i] describe the father of node i on tree.
Next line there are n positive integers v[2] ,v[3], …, v[n], v[i] describe the value of node i.
n<=100000, f[i]<i, v[i]<=100000
 

 

Output
Your output should include n lines, for i-th line, output the max number that node i heard.
For the nodes who heard nothing, output -1.
 

 

Sample Input
4 1 1 3 4 1 6 9
 

 

Sample Output
2 -1 3 -1
 

 

Source
 
思路:
对每个节点建一棵权值线段树,线段树上插入该点权值的所有的质因数。
 
更新答案时,我们从底层网上更新,每次将所有的质因数更新到其父节点,同时保留一个最大值。
 
总体大概就是这样,具体细节需要在敲的时候注意下。
 
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int maxm=maxn*400;
struct node {int u,v,next;}e[maxn];
int head[maxn],cnt=0;
inline void add(int u,int v){e[cnt]=node{u,v,head[u]},head[u]=cnt++;}
vector<int>vec[maxn];
inline void init(){
    for (int i=1; i<maxn; i++) vec[i].push_back(1);
    for (int i=2; i<maxn; i++){
        vec[i].push_back(i);
        for (int j=i+i; j<maxn; j+=i)
            vec[j].push_back(i);
    }
}
int root[maxn],tot,ls[maxm],rs[maxm],sum[maxm];
inline void pushUp(int rt){
    if(ls[rt] && rs[rt]) sum[rt]=max(sum[ls[rt]],sum[rs[rt]]);
    else if(ls[rt]) sum[rt]=sum[ls[rt]];
    else if(rs[rt]) sum[rt]=sum[rs[rt]];
}
void build(int &rt,int l,int r,int pos){
    if(!rt) rt=++tot;
    if(l==r){
        sum[rt]=pos;
        return ;
    }
    int mid=l+r>>1;
    if(pos<=mid) build(ls[rt],l,mid,pos);
    if(pos>mid)  build(rs[rt],mid+1,r,pos);
    pushUp(rt);
}
int merge(int rt,int prt,int &ans){
    if(!rt||!prt) return rt^prt;
    if(sum[rt]==sum[prt]) ans=max(ans,sum[rt]);
    if(ls[rt] | ls[prt]) ls[rt]=merge(ls[rt],ls[prt],ans);
    if(rs[rt] | rs[prt]) rs[rt]=merge(rs[rt],rs[prt],ans);
    pushUp(rt);
    return rt;
}
int n,ans[maxn];
void dfs(int u){
    ans[u]=-1;
    for (int i=head[u];~i;i=e[i].next){
        dfs(e[i].v);
        root[u]=merge(root[u],root[e[i].v],ans[u]);
    }
}
int main(){
    memset(head,-1,sizeof(head));
    cnt=0,tot=0;
    init();
    scanf("%d",&n);
    for (int fa,i=2; i<=n; i++){
        scanf("%d",&fa);
        add(fa,i);
    }
    for (int x,i=1; i<=n; i++){
        scanf("%d",&x);
        root[i]=0;
        for (int j=0; j<vec[x].size(); j++)
            build(root[i],1,maxn,vec[x][j]);
    }
    dfs(1);
    for (int i=1; i<=n; i++) printf("%d\n",ans[i]);
    return 0;
}
View Code

 

posted @ 2018-08-26 23:36  Acerkoo  阅读(464)  评论(0编辑  收藏  举报