1. 程式人生 > 實用技巧 >[hdu-6867]Tree 樹上字首和 2020多校9

[hdu-6867]Tree 樹上字首和 2020多校9

【題目連結】:http://acm.hdu.edu.cn/showproblem.php?pid=6867

【題目】:

Problem Description You are given a tree consisting ofnvertices numbered1tonrooted at node1. The parent of thei-th vertices ispi. 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 thatxcan move toythrough the edges after adding the edge. Note thatxcan also move tox.
Input The first line contains one integerT(1T100000)— the number of test cases.
The first line of each test case contains only one integern(1n5×105)— the number of vertices in the tree.
The second line of each test case containsn1integersp2,p3,,pn(1pi<i)— the parent of each non-root node.
The sum ofnover all test cases does not exceed106.
Output PrintTintegers — for each test case output the maximum number of pairs(x,y)that verticesxcan move toyafter adding one edge.
Sample Input 2 5 1 1 2 2 6 1 2 3 1 3 Sample Output 17 26 Source 2020 Multi-University Training Contest 9

【題意】:給一個根節點為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\n",ans);
    }
    return 0;
}
/*
14
1 1 2 2 3 3 3 3 3 3 3 7 5
*/