BZOJ1131 [POI2008]Sta 其他
阿新 • • 發佈:2017-12-21
brush algorithm 最大 根節點 cpp sum 深度 同時 line
原文鏈接http://www.cnblogs.com/zhouzhendong/p/8081100.html
題目傳送門 - BZOJ1131
題意概括
給出一個N個點的樹,找出一個點來,以這個點為根的樹時,所有點的深度之和最大。
題解
嘻,這題不卡棧。
假設以1為根
先跑一遍dfs,算出每一個子樹的節點數size,同時算出以1為根節點的深度和。
然後再跑一遍dfs,這一回,我們就可以算答案了。
假設我們要把樹根從一條邊的一個節點移向另一個節點,那麽,這兩個節點為根的答案差就是這條邊兩端的節點個數差。因為其中一個節點代表的子樹上的節點都要多走一步到根,而另一邊少走一步。這樣就可以在O(n)的時間復雜度內solve這一題了。
代碼
#include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> using namespace std; typedef long long LL; const int N=1000005; struct Gragh{ int cnt,y[N*2],nxt[N*2],fst[N]; void clear(){ cnt=0; memset(fst,0,sizeof fst); } void add(int a,int b){ y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt; } }g; int n,size[N],ans; LL sum[N],res[N]; void dfs1(int rt,int pre){ size[rt]=1,sum[rt]=0; for (int i=g.fst[rt];i;i=g.nxt[i]) if (g.y[i]!=pre){ int s=g.y[i]; dfs1(s,rt); size[rt]+=size[s]; sum[rt]+=sum[s]; } sum[rt]+=size[rt]-1; } void dfs2(int rt,int pre){ res[rt]=res[pre]-size[rt]+(n-size[rt]); if (!ans||res[rt]>res[ans]||(res[rt]==res[ans]&&rt<ans)) ans=rt; for (int i=g.fst[rt];i;i=g.nxt[i]) if (g.y[i]!=pre) dfs2(g.y[i],rt); } int main(){ g.clear(); scanf("%d",&n); for (int i=1,a,b;i<n;i++){ scanf("%d%d",&a,&b); g.add(a,b); g.add(b,a); } dfs1(1,0); ans=0; res[0]=sum[1]+n; dfs2(1,0); printf("%d",ans); return 0; }
BZOJ1131 [POI2008]Sta 其他