2020hdu多校第九场比赛及补题

第九场是真滴难,hdu多校很多场都是榜一前一小时内过6题左右,这场榜前三都是前一小时内只过了一题OAO

1001 Tree

如题名,先给了一颗树,然后这棵树看成是个有向图,方向为父亲指向儿子,每个点都有贡献,其贡献为这个点在图中能到达的点的个数

嗯,看起来贡献就是子树的大小siz[node]

然后,还给了你一条有向边,这条有向边的起点和终点是你自己选的,你要使所有点的贡献加起来最大,求最大的贡献是多少

分析:

  • 选起点为u,终点为v,那么贡献受到影响的点有 u 还有 u 的所有父亲节点,且受影响的点它的贡献是只增不减的,所以 选u的儿子为起点  比  选u为起点更优, 因为多了一个受影响的点,且原先的那些点的受影响程度不变,所以要选一个叶子节点作为起点
  • 未受影响的点,能到达的点就是以它为根节点的子树上的所有点
  • 受影响的点,能到达的点是 以它为根节点的子树上的所有点 和 以v为根节点的子树上的所有点 的并集, 所以 选v的父亲为终点 比 选v为终点 更优 ,所以要选根节点作为终点

做法:

  枚举所有叶子节点为起点(枚举所有节点为起点也行),以根节点为终点的贡献

直接dfs一遍就行了

这题我们wa了几遍,原因是我没分析完就下结论了,我当时得出的结论是,选深度最大的点为起点,根节点为终点,然后wa了,之后我造了个1e5的一条链为数据,然后程序没跑出来,队友说是爆栈了,然后我就以为wa了是我用dfs爆栈了的原因,然后我观察到数据的输入有特殊要求,发现不用dfs也能做,然后又wa了,然后才发现是我分析的不够QAQ

 

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
const int MAXN = 5e5+7;
int deep[MAXN],son[MAXN],fa[MAXN];
long long su[MAXN];
bool bz[MAXN];
int main()
{
	//freopen("cccc.out","r",stdin);
	int T, n;
	cin>>T;
	while(T--){
		scanf("%d",&n);
		for(int i = 1;i <= n;i++) {
			bz[i] = false;
			son[i] = 0;
			su[i] = 0;
		}
		fa[1] = 0;
		deep[1] = 1;
		int x;
		for(int i = 2;i<=n;i++){
			scanf("%d",&x);
			fa[i] = x;
			deep[i] = deep[x] + 1;
		} 
		long long ans = 0;
		for(int i = n;i;i--){
			son[i]++;
			son[fa[i]] += son[i];
			ans += son[i];
		}
		long long ma = 0;
		for(int i = 1;i<=n;i++){
			su[i] = (long long)son[i] + su[fa[i]]; 
			ma = max(ma,(long long)deep[i]*(long long)n-su[i]);
		}
		ans += ma;
		printf("%lld\n",ans);
	}	
	return 0;
}

  

 1003待补,博弈太难了啊

posted @ 2020-08-29 15:04  beta_dust  阅读(127)  评论(0编辑  收藏  举报