[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 (1≤T≤100000) — the number of test cases.
The first line of each test case contains only one integer n(1≤n≤5×105) — the number of vertices in the tree.
The second line of each test case contains n−1 integers p2,p3,…,pn(1≤pi<i) — the parent of each non-root node.
The sum of n over all test cases does not exceed 106.
The first line of each test case contains only one integer n(1≤n≤5×105) — the number of vertices in the tree.
The second line of each test case contains n−1 integers p2,p3,…,pn(1≤pi<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\n",ans); } return 0; } /* 14 1 1 2 2 3 3 3 3 3 3 3 7 5 */