今年夏天,NOI在SZ市迎來了她30週歲的生日。git
來自全國 n 個城市的OIer們都會從各地出發,到SZ市參加此次盛會。github
全國的城市構成了一棵以SZ市爲根的有根樹,每一個城市與它的父親用道路鏈接。算法
爲了方便起見,咱們將全國的 n 個城市用 1 到 n 的整數編號。其中SZ市的編號爲 1。工具
對於除SZ市以外的任意一個城市 v,咱們給出了它在這棵樹上的父親城市 fv 以及到父親城市道路的長度 sv。優化
從城市 v 前往SZ市的方法爲:選擇城市 v 的一個祖先 a,支付購票的費用,乘坐交通工具到達 a。spa
再選擇城市 a 的一個祖先 b,支付費用併到達 b。以此類推,直至到達SZ市。code
對於任意一個城市 v,咱們會給出一個交通工具的距離限制 lv。blog
對於城市 v 的祖先 a,只有當它們之間全部道路的總長度不超過 lv 時,從城市 v 才能夠經過一次購票到達城市 a,不然不能經過一次購票到達。遞歸
對於每一個城市 v,咱們還會給出兩個非負整數 pv,qv 做爲票價參數。隊列
若城市 v 到城市 a 全部道路的總長度爲 d,那麼從城市 v 到城市 a 購買的票價爲 d * pv+qv。
每一個城市的OIer都但願本身到達SZ市時,用於購票的總資金最少。
你的任務就是,告訴每一個城市的OIer他們所花的最少資金是多少。
輸入格式:
第 1 行包含2個非負整數 n,t,分別表示城市的個數和數據類型(其意義將在後面提到)。
輸入文件的第 2 到 n 行,每行描述一個除SZ以外的城市。
其中第 v 行包含 5 個非負整數 f_v,s_v,p_v,q_v,l_v,分別表示城市 v 的父親城市,它到父親城市道路的長度,票價的兩個參數和距離限制。
請注意:輸入不包含編號爲 1 的SZ市,第 2 行到第 n 行分別描述的是城市 2 到城市 n。
輸出格式:
輸出包含 n-1 行,每行包含一個整數。
其中第 v 行表示從城市 v+1 出發,到達SZ市最少的購票費用。
一樣請注意:輸出不包含編號爲 1 的SZ市。
7 3 1 2 20 0 3 1 5 10 100 5 2 4 10 10 10 2 9 1 100 10 3 5 20 100 10 4 4 20 0 10
40 150 70 149 300 150
從每一個城市出發到達 SZ的路線以下(其中箭頭表示一次直達):
城市 2:只能選擇 2 → 1,花費爲 2 × 20 + 0 = 40。
城市 3:只能選擇 3 → 1,花費爲 5 × 10 + 100 = 150。 城 市 4 : 由 於 4 + 2 =6 ≤ l4 = 10,故能夠選擇 4 →1。
若選擇 4 → 1,花費爲 (4 +2) × 10 + 10 = 70 ; 若選 擇 4 → 2 → 1,則花費爲 (4 ×10 + 10) + (2 × 20 + 0) =90;所以選擇 4 → 1。
城市 5:只能選擇 5 →2 → 1 , 花費爲 (9 × 1 +100) + (2 × 20 + 0) = 149;沒法選擇 5 → 1,由於 l5 =10,而城市 5 到城市 1 總路程爲 9 + 2 = 11 > 5,城市 5 不能直達城市 1。
城市 6:若選擇 6 → 1,花費爲 (5 + 5) × 20 + 100 = 300;若選擇 6 → 3 →1,花費爲 (5 × 20 + 100) + (5 × 10 + 100) = 350;所以選擇 6 → 1。
城市 7:選擇 7 → 4 → 1,花費爲 (4 × 20 + 0) + ((4 + 2) × 10 + 10) = 150;
其餘方案均比該方案差。
數據規模
首先,你要學會DP
記\(dp(i)\)表示\(i\)節點到達首都的最小費用
那麼,有轉移方程:
\(dp(i)=min(dp(j)+p(i)*dis(i,j)+d(i))\)
考慮轉化成斜率優化:
記\(dep(i)\)表示\(i\)節點到根的深度
\(dp(i)=dp(j)+p(i)*(dep(i)-dep(j))+d(i)\)
\(dp(i)=dp(j)+p(i)*dep(i)-p(i)*dep(j)+d(i)\)
\(dp(j)=p(i)*dep(j)+dp(i)-d(i)-p(i)*dep(i)\)
那麼,如今就是一個斜率優化的式子了。
其中,\(x\)是\(dep(j)\),單調遞增
其中,\(k\)是\(p(i)\),沒有任何單調性
只不過題目中有\(l(i)\)這個距離限制。
嗯。。。。怎麼辦?
凸包是不支持刪除的。
所以咱們要另闢蹊徑。
作法一:
樹鏈剖分
直接上樹剖後,發現每次查詢的凸包都對應原樹中的一條鏈。
那麼,咱們讓樹剖後的線段樹區間\(l...r\)中存下點\(dfn[l]...dfn[r]\)所造成的凸包。
對於每一個點,每次會查到\(\log n\)條重鏈,每次重鏈要查詢\(\log n\)個區間,每次區間中在凸包上三分須要\(\log n\)的時間
所以,總耗時\(O(n* (\log n)^{3})\)
過不去,不存在的,樹剖這種東西怎麼可能想卡就卡!!!
補充:常數優化:
每次線段樹中的凸包合併時,由於一個區間的全部元素沒有都被訪問過期,就必定不會查到這段區間。
所以,能夠選擇在左右兩個子區間的全部元素都被訪問過期,選擇\(O(n)\)的合併凸包
時間複雜度:\(O(n*(\log n)^{3})\)
空間複雜度:\(O(n* \log n)\)
作法二:
可持久化線段樹+平衡樹
樹剖的理論複雜度過不去???
若是你真的對理論複雜度有需求,那麼不妨來聽下如下作法。
發現,其實咱們只須要對當前\(dfs\)鏈維護一棵線段樹,這樣子,查詢的複雜度能降到\(O((\log n)^{2})\)
可是,爲了不元素過多(也能夠說發現父親的元素同本身變化不大),所以能夠用可持久化來維護。
時間複雜度:\(O(n* (\log n)^{2})\)
空間複雜度:\(O(n *(\log n)^{2})\)
作法三:
可持久化線段樹+單調隊列
樹套樹常數大??
不要緊,這題有一個很是重要的特殊性質:\(x\)單增
所以,咱們只須要一個單調隊列就能夠表示一個凸包了。
具體而言,能夠選擇用線段樹來實現這個隊列。
然而,這題還有特殊性:鏈都是父親來的,也就是說咱們只須要訪問特定的版本。
對於上個版本,咱們只須要記錄新插入的點替代了誰。
固然這樣子,插入時要二分插入的位置。
時間複雜度:\(O(n* (\log n)^{2})\)
空間複雜度:\(O(n * \log n)\)
作法四:
點分治+可持久化平衡樹
首先套一個點分,思考點份內部幹什麼。
很天然地,想到把祖先所在的鏈找出來,更新下面全部的子樹。
爲何正確呢?
證實一下兩個結論:
1.全部祖先節點優先被更新
這準確來講並非一個結論,但它告訴咱們,先遞歸祖先所在的子樹,再處理本身
2.一個點能夠被全部的祖先更新
若是當前分治結構還有祖先無法更新,那麼這些祖先會在下層分治結構中成爲更新點從而更新當前節點。
所以,點分是沒有問題的。
如何知足限制?
把全部的祖先建出一棵可持久化平衡樹,在上面查詢便可。
作法五:
點分治+CDQ分治
把上面的可持久化平衡樹用CDQ分治來替代便可
作法六:
點分治+三分
把全部凸包按順序加入,全部點按順序在上面三分
作法七:
點分治+亂搞
莫名其妙的亂搞。
複雜度最壞\(O(n^{2})\),不知爲什麼能過,並且很快。。。
分治算法的時間複雜度爲\(O(n * (\log n)^{2})\)
空間複雜度爲\(O(n)\)
是最優的複雜度
補充:
當你的算法涉及\(O(n)\)建凸包時,請當心處理斜率的關係