題目描述
今天是世界水日,著名的水題資源專家蟈蟈大臣發起了水題走四方活動,向全世界發放成千上萬的水題。
蟈蟈大臣是家裡蹲大學的教授,當然不願意出門發水題啦!所以他委託他的助手歐姆來發。
助手歐姆最近做 ur #6 被狗狗傳染了懶癌,當然不願意出門發水題啦!所以他請來了高手 —— 地卜師。
全世界一共 n
'>n
個城市,編號分別為 1,…
,n'>1,…,n
。城市之間由雙向道路相連,形成了一棵樹。如果這棵樹以 1
'>1
為根,則除 1
'>
1 以外每個結點 v
'>v
的父親結點的編號 p
v'>pv
滿足 p
v<
v'>pv
。由於地卜師掌握了轉殖的核心科技,把自己完全複製了乙份,他和他的分身一共兩個地卜師一起出去執行任務。
現在,兩個地卜師都站在 1
'>
1 號城市。地卜師可以沿道路行走,從乙個城市移動到另乙個城市。走一條道路需要耗時 1
'>
1 小時。當然,地卜師可以停留在某個城市不動。每到乙個沒有發放水題的城市,地卜師都會發水題。在乙個城市裡發水題的時間不計。
由於地卜師有強迫症,他沿道路移動時總是從乙個城市移動到編號更大的城市。即總是從乙個結點移動到它的兒子結點。地卜師和他的分身可以同時移動。
但是地卜師這樣好像不一定能經過所有的城市?沒關係!地卜師會瞬移。如果某個時刻兩個地卜師都在某個城市裡(而不是在去某個城市的道路上),那麼其中乙個地卜師可以瞬移到另乙個地卜師所在的城市。瞬移所需的時間不計。
現在地卜師想知道,要想順利給每個城市都發放水題,最短需要多少個小時。
歐姆當然知道怎麼計算啦!但是他想考考你。
題解
神仙題.png。
我們可以先考慮最優解是怎麼走出來的。
先是這個人和它的分身,初步的想法是他們倆來到了乙個節點,然後分身去遍歷這顆子樹的一些兒子中的葉子結點。
最後剩乙個兒子,然後它倆一塊走到下乙個兒子裡面。
但是這種想法少考慮了一些情況(反例就不說了,也就是說不能只考慮往兒子走)。
我們可以將兩個人同時停留的地方稱作關鍵點,顯然所有的關鍵點都在一條鏈上。
那麼分身應該遍歷這顆子樹減去下一顆關鍵點所在子樹的那顆子樹的所有葉子結點。
就是在分身遍歷最後乙個葉子的時候,這個人可以同時往下乙個關鍵點走,等到兩個人都到了自己該到的地方,分身再tp到這個人那裡。
然後有乙個初步的dp想法,就是設dp[i]表示i是乙個關鍵點,兩個人第一次到這個點所用的最小時間。
轉移:nl:當前子樹內的葉子節點個數,ds:當前子樹內葉子結點的深度和,dm[u][v]:u的子樹扣掉v的子樹後最深的葉子結點的深度,d:節點深度。
更正:上面的第二個min為max。
後面那個東西是在討論這個人和分身誰先到目的地。
這個dp是n^2的,好像有各種高科技的優化辦法然而並不會。。。
我們發現這個式子前面那一坨好像可優化性不大。
考慮後面那個max可不可以為0,那麼相當於是說找到乙個祖先u使得d[v]<=dm[u,v]。
如果我們對於每個點都找出這個祖先的話,轉移就輕鬆完成了。
我們考慮是不是所有點都能找到這個祖先,肯定不是的,當乙個點的deep滿足沒有其他點和它deep相等時這個點是沒有這種祖先的。
這樣的點有什麼神奇的規律?它們是連續的一條鏈,就是這個樣子的。
一棵樹下面多出來的這條鏈。
因為我們是在葉子的位置統計答案,那麼有結論,最優解肯定不在這種葉子上(想想為什麼)。
那麼我們的任務就變成找這種神奇祖先了。
首先這種神奇祖先肯定是越低越好。
我們可以維護乙個鍊錶表示還沒找到祖先的節點,在子樹合併的時候互相更新一下(因為兩顆子樹的maxdeep都可以作為更新答案的條件)。
這是最多隻會有一顆子樹內有節點沒有找到祖先(想想為什麼),所以我們維護的複雜度是線性的。
**
#include#include#define n 5000009
#define inf 1e18
using
namespace
std;
typedef
long
long
ll;inline ll rd()
while(isdigit(c))
return f?-x:x;
}ll n,deep[n],mx_deep[n],sum_deep[n],cnt[n],dp[n];
intnxt[n],up[n],son[n],tot,fa[n];
char s[n<<1
];int
main()
else v=fa[v];
}for(int i=2;i<=n;++i)
for(int i=n;i>=2;--i)
int now=i;
while(now&&deep[now]<=mx_deep[fa[i]])
while(nxt[fa[i]]&&deep[nxt[fa[i]]]<=mx_deep[i])
if(now)nxt[fa[i]]=now;
mx_deep[fa[i]]=max(mx_deep[fa[i]],mx_deep[i]);
sum_deep[fa[i]]+=sum_deep[i];
cnt[fa[i]]+=cnt[i];
}ll ans=inf;
for(int i=2;i<=n;++i)
if(n==1)
cout
<
return0;
}
uoj84 水題走四方
瞬移後無法區分兩者,分開時不妨稱下一次瞬移的為分身,即僅允許分身瞬移回本身 考慮本身,即從根節點出發向下移動的一條路徑,並稱路徑上分身曾瞬移到的點為關鍵節點 包括根節點 對關鍵節點dp,定義 f 表示當前兩者均在 k 且 k 子樹外所有點均被經過的最短時間 列舉上乙個關鍵節點,分析兩者的移動,不難得...
poj入門水題整理7
1.3507 judging olympia 解法 就是求平均數 2.3325 icpc score totalizer software 解法 就是去掉乙個最高分去掉乙個最低分求平均值 3.2013 symmetric order 描述 原先的系統是將一串人名以長度公升序輸出,現在老闆希望能夠以對...
xsy1378 水題7號 貪心
題目大意 有 m 組約束關係 x i,y i 你要構造乙個排列,滿足數 x i 出現在數 y i 前面,請使得這個排列字典序最小,請輸出這個排列。無解請輸出 1。資料範圍 n,m 10 5 我們把約束關係 x i,y i 視作從 y i 連向 x i 的有向邊,於是我們得到了乙個有向圖,無解情況下該...