2020hdu多校第九場比賽及補題
阿新 • • 發佈:2020-08-29
第九場是真滴難,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待補