1. 程式人生 > 實用技巧 >2020hdu多校第九場比賽及補題

2020hdu多校第九場比賽及補題

第九場是真滴難,hdu多校很多場都是榜一前一小時內過6題左右,這場榜前三都是前一小時內只過了一題OAO

1001Tree

如題名,先給了一顆樹,然後這棵樹看成是個有向圖,方向為父親指向兒子,每個點都有貢獻,其貢獻為這個點在圖中能到達的點的個數

嗯,看起來貢獻就是子樹的大小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待補