今年夏天,NOI在SZ市迎來了她30週歲的生日。來自全國 n 個城市的OIer們都會從各地出發,到SZ市參加此次盛會。c++
全國的城市構成了一棵以SZ市爲根的有根樹,每一個城市與它的父親用道路鏈接。爲了方便起見,咱們將全國的 n 個城市用 1 到 n 的整數編號。其中SZ市的編號爲 1。對於除SZ市以外的任意一個城市 v,咱們給出了它在這棵樹上的父親城市 fv 以及到父親城市道路的長度 sv。git
從城市 v 前往SZ市的方法爲:選擇城市 v 的一個祖先 a,支付購票的費用,乘坐交通工具到達 a。再選擇城市 a 的一個祖先 b,支付費用併到達 b。以此類推,直至到達SZ市。算法
對於任意一個城市 v,咱們會給出一個交通工具的距離限制 lv。對於城市 v 的祖先 a,只有當它們之間全部道路的總長度不超過 lv 時,從城市 v 才能夠經過一次購票到達城市 a,不然不能經過一次購票到達。對於每一個城市 v,咱們還會給出兩個非負整數 pv,qv 做爲票價參數。若城市 v 到城市 a 全部道路的總長度爲 d,那麼從城市 v 到城市 a 購買的票價爲 dpv+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市。spa
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 10code
40
150
0
149
300
150blog
對於全部測試數據,保證 0≤pv≤106,0≤qv≤1012,1≤fv<v;保證 0<sv≤lv≤2×1011,且任意城市到SZ市的總路程長度不超過 2×1011。遞歸
輸入的 t 表示數據類型,0≤t<4,其中:
當 t=0 或 2 時,對輸入的全部城市 v,都有 fv=v-1,即全部城市構成一個以SZ市爲終點的鏈;
當 t=0 或 1 時,對輸入的全部城市 v,都有 lv=2×1011,即沒有移動的距離限制,每一個城市都能到達它的全部祖先;
當 t=3 時,數據沒有特殊性質。
n=2×10^5
經典好題吧
知識點很全
首先考慮在一條鏈上怎麼作?
斜率優化是一眼的
可是在樹上怎麼辦?
咱們要用一個節點的全部父親來更新這個節點的dp值
考慮下分治算法來優化這個過程
在斜率優化的處理方式中有一種經典操做叫cdq分治
就是先處理一部分而後用這一部分更新剩下的部分,而後再遞歸處理剩下的部分
這裏咱們把問題模型抽象出來
若是把樹劃分紅幾個部分的話,咱們考慮一個事情,就是說用來更新的祖先是一條鏈,能夠更新到的兒子是一個子樹
咱們把祖先的鏈當成前一個部分,兒子當作另外一個部分
也就是說咱們先處理出前一個部分的全部信息,而後再用來更新兒子
考慮分治的過程
當前分治的樹根是u,分治中心是rt
那麼顯然\([rt,u]\)這條鏈上的信息咱們須要先處理出來
因此咱們優先遞歸除了rt子樹外的全部節點
而後再把\([rt,u]\)這一條鏈提出來更新rt的子樹
注意由於有一個最大長度限制
因此咱們進行更新的時候必定要注意把子樹節點按照必定順序排好,使得能夠更新每個節點的祖先數量單調不降
而後就對祖先維護凸殼就行了
注意一下點積不要爆longlong,用longdouble
還有找重心的時候若是當前節點siz是1須要特判一下不能做爲重心
#include<bits/stdc++.h> using namespace std; typedef long double ld; typedef long long ll; ll read() { ll res = 0, w = 1; char c = getchar(); while (!isdigit(c) && c != '-') c = getchar(); if (c == '-') c = getchar(), w = -1; while (isdigit(c)) res = (res << 1) + (res << 3) + c - '0', c = getchar(); return w * res; } const ll INF_of_ll = 1e18; const ll N = 2e5 + 10; struct Node { ll id, val; Node() {} Node(ll id, ll val): id(id), val(val) {} } rque[N]; bool operator < (const Node &a, const Node &b) { return a.val > b.val; } struct Vector { ll x, y; Vector() {} Vector(ll x, ll y): x(x), y(y) {} } lque[N]; Vector operator - (const Vector &a, const Vector &b) { return Vector(a.x - b.x, a.y - b.y); } ld operator * (const Vector &a, const Vector &b) { return (ld) a.x * b.y - (ld) a.y * b.x; } struct Edge { ll v, w, nxt; } E[N << 1]; ll topl, topr; ll head[N], tot = 0; ll n, prt[N], p[N], q[N], limit[N], dp[N]; ll siz[N], dis[N], F[N], vis[N], siz_all; void addedge(ll u, ll v, ll w) { E[++tot] = (Edge) {v, w, head[u]}; head[u] = tot; } void getsiz(ll u) { siz[u] = 1; for (ll i = head[u]; i; i = E[i].nxt) { ll v = E[i].v; if (vis[v]) continue; dis[v] = dis[u] + E[i].w; getsiz(v); siz[u] += siz[v]; } } void getrt(ll u, ll &rt) { F[u] = siz_all - siz[u]; for (ll i = head[u]; i; i = E[i].nxt) { ll v = E[i].v; if (vis[v]) continue; getrt(v, rt); F[u] = max(F[u], siz[v]); } if (F[u] < F[rt] && siz[u] > 1) rt = u; } void dfs(ll u) { rque[++topr] = (Node) {u, dis[u] - limit[u]}; for (ll i = head[u]; i; i = E[i].nxt) if (!vis[E[i].v]) dfs(E[i].v); } ll calc(ll v, Vector u) { return u.y + (dis[v] - u.x) * p[v] + q[v]; } void solve(ll u, ll cursiz) { if (cursiz == 1) return; ll rt = 0; getsiz(u); F[rt] = siz_all = cursiz; getrt(u, rt); for (ll i = head[rt]; i; i = E[i].nxt) vis[E[i].v] = 1; solve(u, cursiz - siz[rt] + 1); topl = topr = 0; for (ll i = head[rt]; i; i = E[i].nxt) dfs(E[i].v); sort(rque + 1, rque + topr + 1); ll cur = rt; lque[0] = Vector(dis[rt] + 1, INF_of_ll); for (ll i = 1; i <= topr; i++) { while (cur != prt[u] && dis[cur] >= rque[i].val) { Vector now(dis[cur], dp[cur]); while (topl > 1 && (lque[topl] - lque[topl - 1]) * (now - lque[topl - 1]) > 0.0) topl--; lque[++topl] = now; cur = prt[cur]; } if (topl) { ll l = 1, r = topl, res = 1, now = rque[i].id; while (l <= r) { ll mid = (l + r) >> 1; if (calc(now, lque[mid]) <= calc(now, lque[mid - 1])) res = mid, l = mid + 1; else r = mid - 1; } dp[now] = min(dp[now], calc(now, lque[res])); } } for (ll i = head[rt]; i; i = E[i].nxt) solve(E[i].v, siz[E[i].v]); } int main() { #ifdef dream_maker freopen("input.txt", "r", stdin); #endif n = read(); ll typ = read(); for (ll i = 2; i <= n; i++) { prt[i] = read(); ll w = read(); addedge(prt[i], i, w); p[i] = read(); q[i] = read(); limit[i] = read(); dp[i] = INF_of_ll; } solve(1, n); for (ll i = 2; i <= n; i++) printf("%lld\n", dp[i]); return 0; }