BZOJ 1509 逃學的小孩 樹型dp

2022-06-01 07:15:10 字數 1400 閱讀 4044

傳送門

在一棵樹中, 每條邊都有乙個長度值, 現要求在樹中選擇 3 個點 x、y、 z , 滿足 x 到 y 的距離不大於 x 到 z 的距離, 且 x 到 y 的距離與 y 到 z 的距離之和最大,求這個最大值。

在一篇**中看到了這道題,於是就來做做。

從這題中可以得到很多啟示,光看題意一定會想到列舉點來做,不過如果列舉三點的話就爆了,於是列舉的那個點就成了解題的關鍵。我們發現,所有的答案無非就兩種:

(紅色代表特殊點,黃色代表起點)

他們都是最短路徑 + 次短路徑 * 2 + 最長路徑(第一種情況相當於最短路徑為0),於是第一種情況可以歸到第二種情況中,這樣一定是滿足題意的條件下最優的。那麼直接分析第二種情況:

發現無論是第一種還是第二種都有乙個特殊點---分叉點a,如果用分叉點來表示距離那麼|xy| + |yz| = |xa| + 2|ya| + |za|,要讓答案最大,也就是讓三點到a的距離最大。

這下就好辦了,求最大距離---樹型dp:這樣的三條鏈又有兩種情況:

第一種是三條鏈都在子樹中,第二種是一條在子樹外,兩條在子樹中。那麼進行兩遍dp:第一遍從求u向下的三條不在同一顆子樹的三條最長鏈(最長,次長,次次長),第二遍求u向上的一條最長鏈。

最後統計u分叉點的答案時,取這四條鏈的前三大,答案更新為最短路徑 + 次短路徑 * 2 + 最長路徑

改了我乙個多小時,結果發現是輸出優化的int沒有改成long long!!

#includeusing namespace std;

#define maxn 200050

typedef long long ll;

namespace io

inline void wr(ll x)

}using namespace io;

int n, m;

typedef pairp;

vectoradj[maxn];

ll dp[maxn][5], ans;

inline void dfs1(int u, int f)

else if(dp[v][1] + t > dp[u][2])

else if(dp[v][1] + t > dp[u][3]) }}

inline void dfs2(int u, int f)

}int main()

dfs1(1, 0);

dfs2(1, 0);

for(int i = 1; i <= n; i++)

wr(ans);

return 0;

}

BZOJ1509 NOI2003 逃學的小孩

第一行是兩個整數n 3 n 200000 和m,分別表示居住點總數和街道總數。以下m行,每行給出一條街道的資訊。第i 1行包含整數ui vi ti 1 ui,vi n,1 ti 1000000000 表示街道i連線居住點ui和vi,並且經過街道i需花費ti分鐘。街道資訊不會重複給出。僅包含整數t,即...

NOI2003 樹的直徑 逃學的小孩

原題鏈結 分享題說實話最開始都沒什麼思路,之前的大部分基本都看了一下題解啟發思路。但這道題我可以大聲而驕傲地說 它 是 我 完 完 全 全 自 己 做 出 來 的 當然,代價就是vjudge上wa了5遍,洛谷上wa了1遍,坑殺了我一節半課的時間。那麼,轉到正題,思路是怎麼樣的呢?首先可見這個圖是一棵...

NOI2003 逃學的小孩(樹的直徑)

chris家的 鈴響起了,裡面傳出了chris的老師焦急的聲音 喂,是chris的家長嗎?你們的孩子又沒來上課,不想參加考試了嗎?一聽說要考試,chris的父母就心急如焚,他們決定在盡量短的時間內找到chris。他們告訴chris的老師 根據以往的經驗,chris現在必然躲在朋友shermie或ya...