题意,给一个有向树,判断加一个有向边之后,使得(x,y)对最大,x,y表示x能到达y。
思路,对于根节点,它能到达每一个节点(最多),所以我们可以把叶子节点和根节点链接起来形成一个环,就会得到尽可能多的(x,y)。
默认将自己也作为子树的一个节点.(后面处理防止(x,x)重复计算)
链接后,对于叶子节点,它能够多到达所有的不是它子树的节点,对于叶子节点的父节点,它能多到达所有的不是它子树的结点,…。
所以可以用dfs求出 每个节点子树的大小,
再dfs求出某条到叶子节点路径的
∑
(
n
−
s
i
z
[
]
)
\sum (n-siz[])
∑(n−siz[]) 最后取一下max。
代码:
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
#define int long long
#define sc scanf
#define pf printf
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned long long LL;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int mod = 998244353;
const int N = 500010;
int e[N],ne[N],h[N],idx=1;
int siz[N],ans,n,a;
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int dfs_size(int u){
siz[u] = 1;
for(int i=h[u];i;i=ne[i])
siz[u] += dfs_size(e[i]);
return siz[u];
}
void dfs_ans(int u,int sum){
ans = max(sum,ans);
for(int i=h[u];i;i=ne[i]) dfs_ans(e[i],sum+n-siz[e[i]]);
}
signed main(){
IOS;
#ifdef ddgo
freopen("C:/Users/asus/Desktop/ddgoin.txt","r",stdin);
#endif
int tt; cin>>tt;
while(tt --){
cin>>n;
for(int i=0;i<=n;i++) h[i] = 0; idx = 1;//初始化
for(int i=2;i<=n;i++) cin>>a,add(a,i);
ans = 0;
dfs_size(1); dfs_ans(1,0);
for(int i=1;i<=n;i++) ans += siz[i];//加上本来就可以到达的。
cout<<ans<<endl;
}
return 0;
}