HDU 6430 Problem E. TeaTree 启发式合并

Problem E. TeaTree
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 647 Accepted Submission(s): 232

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
2018 Multi-University Training Contest 10

Recommend
chendu | We have carefully selected several similar problems for you: 6437 6436 6435 6434 6433

题意:
给出一颗树,给出每个点的val,要求输出树上所有点的最大价值,最大价值定义为
ans[X]=max(gcd(val[i],vaj[j])) i,j 满足 lca(i,j) = X
题意:
比赛的时候就一直在讨论启发式合并该怎么写,但是怎么也没想到O(1)的答案更新方法,只会用set维护答案,感觉复杂度是O(n^(3/2)* (log n)^2) 的 怎么样都是不可做的样子。

比赛后听了大神的思路,感觉启发式合并贼tm正确。直接O(n^(1/2))暴力去更新删除就可以了 比赛时候怎么也没想到 ,真的是太2B了。 总复杂度O(n^(3/2)* (log n)) 给了4s 轻轻松松就能过了。
只跑了400ms 快的飞起。
PS: 标程跑了3800ms,结果就给了4s 时限,真的是恶趣味的出题人。 或许 这就是高中生大佬吧。
感觉这个代码改改以后就拿这个当模板了

#include
using namespace std;
const int MAX=3e5+10;
vector<int> V[MAX];
class Edge {
public:
    int v,next;
    long long w;
};
int n;
int tot;
int head[MAX];
Edge edge[MAX<<1];
long long values[MAX];
void init() {
    memset(head,-1,sizeof head);
    tot=0;
}
void add(int u,int v) {
    edge[tot].v=v;
    edge[tot].next=head[u];
    head[u]=tot;
    tot++;
}
int sz[MAX],wson[MAX];
void dfs1(int u,int pre) {
    sz[u]=1;
    for(int i=head[u]; i!=-1; i=edge[i].next) {
        int v = edge[i].v;
        if(v==pre) continue;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(sz[v]>sz[wson[u]]) wson[u]=v;
    }
}
int val[MAX];
int vis[MAX];
int num[MAX];
int divs[MAX];
int tmp ;
vector<int> temp;
void add_node(int u) {
    num[val[u]]++;
    int cnt;
    if(num[val[u]]==1) {
        for(int i=0; ivoid det_node(int u) {
    num[val[u]]--;
    int cnt;
    if(num[val[u]]==0) {
        for(int i=0; ivoid add_tree(int u,int pre) {
    temp.push_back(u);
    for(int i=head[u]; i!=-1; i=edge[i].next) {
        int v = edge[i].v;
        if(v==pre) {
            continue;
        }
        add_tree(v,u);
    }
}
void det_tree(int u,int pre) {
    det_node(u);
    for(int i=head[u]; i!=-1; i=edge[i].next) {
        int v = edge[i].v;
        if(v==pre) {
            continue;
        }
        det_tree(v,u);
    }
}
int ans[MAX];
void dfs2(int u,int pre) {
    if(sz[u]==1) {
        ans[u] = -1;
        add_node(u);
        return;
    }
    for(int i=head[u]; i!=-1; i=edge[i].next) {
        int v = edge[i].v;
        if(v==wson[u] || v==pre) continue;
        dfs2(v,u);
        det_tree(v,u);
    }
    dfs2(wson[u],u);
    tmp=0;
    int cnt;
    for(int i=head[u]; i!=-1; i=edge[i].next) {
        temp.clear();
        int v = edge[i].v;
        if(v==wson[u] || v==pre) continue;
        add_tree(v,u);
        for(int j=0; jfor(int i=0; i//divs[cnt]++;
                if(divs[cnt]) {
                    tmp = max(tmp,cnt);
                }
            }
        }
        for(int j=0; jfor(int i=0; i//divs[cnt]++;
        if(divs[cnt]) {
            tmp = max(tmp,cnt);
        }
    }
    num[val[u]]++;
    if(num[val[u]]==1) {
        for(int i=0; iint main() {
//    freopen("5.in","r",stdin);
//    freopen("5.out","w",stdout);
    for(int i=1; i<100005; i++) {
        for(int j=1; j*i<100005; j++) {
            V[i*j].push_back(i);
        }
    }
    init();
    scanf("%d",&n);
    for(int i=1; i<=n; i++) {
        ans[i]=-1;
    }
    int u;
    for(int i=2; i<=n; i++) {
        scanf("%d",&u);
        add(u,i);
        //add(i,u);
    }
    for(int i=1; i<=n; i++) {
        scanf("%d",&val[i]);
    }
    dfs1(1,-1);
    dfs2(1,-1);
    for(int i=1; i<=n; i++) {
        printf("%d\n",ans[i]);
    }
}

你可能感兴趣的:(启发式合并)