• [hdu-6867]Tree 树上前缀和 2020多校9


    【题目链接】:http://acm.hdu.edu.cn/showproblem.php?pid=6867

    【题目】:

    Problem Description
    You are given a tree consisting of n vertices numbered 1 to n rooted at node 1. The parent of the i-th vertices is pi. You can move from a vertex to any of its children. What's more, you can add one directed edge between any two different vertices, and you can move through this edge too. You need to maximize the number of pairs (x,y) such that x can move to y through the edges after adding the edge. Note that x can also move to x.
     
    Input
    The first line contains one integer T (1T100000) — the number of test cases.
    The first line of each test case contains only one integer n(1n5×105) — the number of vertices in the tree.
    The second line of each test case contains n1 integers p2,p3,,pn(1pi<i) — the parent of each non-root node.
    The sum of n over all test cases does not exceed 106.
     
    Output
    Print T integers — for each test case output the maximum number of pairs (x,y) that vertices x can move to y after adding one edge.
     
    Sample Input
    2 5 1 1 2 2 6 1 2 3 1 3
     Sample Output
    17 26
     
    Source
     

    【题意】:给一个根节点为1的树,每个点可以走向它的儿子。现在你可以加一条有向边。求加完边后最大的能到达的 点对数(x,y)(x可以走到y)。

    【题解】:

    根节点能到达所有点,所以使某个点到达根节点相当于能到达所有点。
    有向边肯定是从某个叶子结点连向根节点,可以使叶子结点到根节点这条路上的点都能从根节点到达这课树上的所有点。

    原来的答案preans有两种计算方法:
    1.每个点能到的点等于以他为根的子树大小tson[x]
    2.每个点对答案的贡献是它的深度deep[x](能到它的点的数量)。

    加上有向边后,从跟到这个叶子结点的点都要对答案进行更新,加上 n-tson[x];
    我们可以用树上前缀和qian[x]求出 叶子到根的tson和
    则答案结果就是对所有叶子结点x,取 preans+max(n*deep[x]-qian[x]);

    ps:答案并不是直接从深度最深的叶子结点连到根(比赛第一发直接这样写了wa掉(计算公式都推出来了却没求所有叶子结点真的蠢哭了)),因为可能这棵子树很大,让这条链上的点走到所有点并不能贡献更多。所以必须把所有叶子结点的结果都算出来取max。

    【AC代码】

    #include<bits/stdc++.h>
    using namespace std;
    int const maxn=5e5+10;
    long long inf=-1e17;
    int tot,head[maxn],n,deep[maxn],tson[maxn],hson,fa[maxn];
    long long qian[maxn];
    long long ans=0,getmi;
    struct edge{
        int v,nxt;
    }e[maxn<<1];
    void build(int x,int y){
        e[++tot].v=y;
        e[tot].nxt=head[x];
        head[x]=tot;
    }
    void TreeSplitDfs1(int x,int d){
        deep[x]=d;
        if(d>deep[hson])hson=x;
        tson[x]=1;
        ans+=d;
        for(int i=head[x];i;i=e[i].nxt){
            int v=e[i].v;
            TreeSplitDfs1(v,d+1);
            tson[x]+=tson[v];
        }
    }
    void TreeSplitDfs2(int x){
        qian[x]=qian[fa[x]]+tson[x];
        for(int i=head[x];i;i=e[i].nxt){
            TreeSplitDfs2(e[i].v);
        }
        if(head[x]==0){
            qian[x]=(long long )deep[x]*(long long )n-qian[x];
            getmi=max(getmi,qian[x]);
        }
    }
    int main(){
        int t;
        scanf("%d",&t);
        fa[1]=0;
        qian[0]=0;
        while(t--){
            scanf("%d",&n);
            ans=0;tot=0;hson=0;
            getmi=inf;
            memset(head,0,sizeof(int)*(n+5));
            for(int i=2;i<=n;i++){
                scanf("%d",&fa[i]);
                build(fa[i],i);
            }
            TreeSplitDfs1(1,1);
            TreeSplitDfs2(1);
            ans+=getmi;
            printf("%lld
    ",ans);
        }
        return 0;
    }
    /*
    14
    1 1 2 2 3 3 3 3 3 3 3 7 5
    */
  • 相关阅读:
    Ruby向Java发起挑战,红色风暴来了吗?
    学习语义网的好书
    Joel给计算机系学生们七条免费的建议
    ruby rails: 一个高开发效率的web开发框架
    推荐:《真正的执行》
    每个java程序员都应该看看Jakarta Commons
    上海IT俱乐部论坛开通了!
    重构的三个层次
    一些蔡志忠先生的漫画书!
    pythonchanllenge: 解决迷题,非常有趣的学习python的方式
  • 原文地址:https://www.cnblogs.com/conver/p/13525406.html
Copyright © 2020-2023  润新知