hdu 6430 Teatree

给定一棵n个点的有根树,1为根节点,每个点有一个点权。询问每个点的子树下任意两个数字的gcd最大是多少。

 

我们可以先把1e5以内所有数字的因数求出来。因为1e5以内数字的因数不超过200个。所以可以暴力做些事情。

树上启发式合并,将重儿子的所有节点的权值以及权值的因子保存下来,然后依次合并轻儿子。

当一个权值第一次出现时,将他所有的因子数量+1。将轻儿子依次合并之前,先看是否有因子出现过,有的话答案更新,然后在合并。

删除的时候当一个数字出现次数为0时,将他的因子数量-1。

 

#include <bits/stdc++.h>
using namespace std;
const int M = 1e5+7;
int head[M],cnt,n,V[M];
vector<int> vec[M],s;
int sz[M],son[M],ans[M],vis[M],num[M];
struct edge{
    int v,next;
}e[M<<1];
void add(int u,int v){
    e[++cnt].v=v;e[cnt].next=head[u];
    head[u]=cnt;
}
void dfs(int u,int fa){
    sz[u]=1;
    son[u]=-1;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v==fa) continue;
        dfs(v,u);
        sz[u]+=sz[v];
        if(son[u]==-1||sz[v]>sz[son[u]]) son[u]=v;
    }
    return ;
}
void add_node(int u){
    num[V[u]]++;
    if(num[V[u]]==1){
        for(int i=0;i<vec[V[u]].size();i++){
            vis[vec[V[u]][i]]++;
        }
    }
}
void del_node(int u){
    num[V[u]]--;
    if(num[V[u]]==0){
        for(int i=0;i<vec[V[u]].size();i++){
            vis[vec[V[u]][i]]--;
        }
    }
}
void del_tree(int u,int fa){
    del_node(u);
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v==fa) continue;
        del_tree(v,u);
    }
}
void add_tree(int u,int fa){
    s.push_back(u);
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v==fa) continue;
        add_tree(v,u);
    }
}
void dfs1(int u,int fa){
    if(sz[u]==1){
        add_node(u);
        return ;
    }
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v==fa||v==son[u]) continue;
        dfs1(v,u);
        del_tree(v,u);
    }
    dfs1(son[u],u);
    int tmp=-1;
    for(int i=head[u];~i;i=e[i].next){
        s.clear();
        int v=e[i].v;
        if(v==fa||v==son[u]) continue;
        add_tree(v,u);
        for(int j=0;j<s.size();j++){
            for(int k=0;k<vec[V[s[j]]].size();k++){
                if(vis[vec[V[s[j]]][k]]) ans[u]=max(ans[u],vec[V[s[j]]][k]);
            }
        }
        for(int j=0;j<s.size();j++) add_node(s[j]);
    }
    for(int i=0;i<vec[V[u]].size();i++){
        if(vis[vec[V[u]][i]]) ans[u]=max(ans[u],vec[V[u]][i]);
    }
    add_node(u);
}
int main(){
    for(int i=1;i<=100005;i++){
        for(int j=1;j*i<=100005;j++){
            vec[i*j].push_back(i);
        }
    }
    scanf("%d",&n);
    cnt=0;memset(head,-1,sizeof(head));
    for(int i=2;i<=n;i++){
        int u;
        scanf("%d",&u);
        add(u,i);
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&V[i]);
        ans[i]=-1;
    }
    dfs(1,-1);//找重儿子 
    dfs1(1,-1);
    for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
    return 0;
} 
View Code

 

posted @ 2018-08-26 18:03  LMissher  阅读(197)  评论(0编辑  收藏  举报