HDU 2196
阿新 • • 發佈:2018-12-16
簡述題意:給一個n個點的帶邊權樹,求每個點能到的最遠距離。
一般題意:
有連續n臺電腦加入,每臺電腦會和之前已經加入的電腦相連,並且邊有一個權值,求每個電腦的最遠的距離。
對於每個點 其到最遠距離只有兩個來源:
1 來自他的子樹, 2來自父節點
對於第一種情況自然很好處理,但是第二種情況,我們就需要考慮了,開始的時候太蠢了,只想到根到當前節點就是最遠,但是沒想到可以是從另外一邊追溯到根節點再到當前節點,那麼我們就得考慮一下如何解決了。
對於一個父節點,我們可能在左子節點或有右側節點或者更多子節點上 找到一個更加好的,思考一下,這不就是找一個次長節點,把她和最長節點連線起來,對於最長那個節點不就是一條最長的從父節點那裡獲得的距離。
所以可能需要3個dp 了,一個存向下遍歷最大,一個存向下次大,最後一個存向上最大。
向上最大我們可以從父節點向下遍歷的時候得出來,所以先跑一邊向下,最後跑一邊向上,得出結果。
當然對於向上遍歷的過程,我們先判斷當前節點是不是對於父節點來講的最大距離點,如果是,就把他和他父節點的次大連起來,否則就把他和最大連起來,求得從父節點那邊獲得最大距離。
很精彩的一道題。。。。
以下為 AC 程式碼
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 1e5+5; struct node { int to,nxt,w; }ed[maxn]; int head[maxn],tot; int dp[maxn][3]; int len[maxn]; void add(int x,int y,int w) { ed[++tot].to = y; ed[tot].nxt = head[x]; ed[tot].w = w; head[x] = tot; } void dfs_down(int u) { int mxx = -1, mx = -1; for(int i=head[u];~i;i=ed[i].nxt) { int v = ed[i].to; dfs_down(v); int tmp = dp[v][0]+ed[i].w; if(mxx <= tmp) { mx = mxx; mxx = tmp; } else if(mx < tmp) mx = tmp; } dp[u][0] = mxx; dp[u][1] = mx; } void dfs_up(int u) { for(int i=head[u];~i;i=ed[i].nxt) { int v = ed[i].to; dp[v][2] = max(dp[u][2] , dp[v][0] + ed[i].w == dp[u][0] ? dp[u][1] : dp[u][0]) + ed[i].w; dfs_up(v); } } int main() { int n; while(~scanf("%d",&n)) { memset(head,-1,sizeof head); tot = 1; for(int v=2;v<=n;v++) { int u,w; scanf("%d%d",&u,&w); add(u,v,w); } dfs_down(1); dp[1][2] = 0; dfs_up(1); for(int i=1;i<=n;i++) printf("%d\n",max(dp[i][0],dp[i][2])); } return 0; }