題目:
題解:
這個很明顯要從上往下DP,而且下面的DP選擇了就可以直接選擇用上面的信息直接轉移了。
大概就是 (dis[i]-dis[j]<=l[i],j=fa[j])
dis[i]當然是距離數組,f[i]就是答案數組啦
按照無關的量放在外面畫柿子吧,
那麼對於一個x=p[i]的情況,k=-dis[j],b=f[j],轉化爲y座標最小。這樣對於fa[i]到pre[i](最高滿足條件的祖先),我們有這些直線,這些直線肯定不會都有用啊,其實是要維護一個下凸殼,然後選擇出在橫座標爲p[i]的情況下最小值所在的直線就ok了。
假設我們已經有一個半平面和橫座標x,那麼我們可以在O(logn)的時間內找到使得y最小的那條線(三分)
既然是樹,那麼我們可以考慮一下樹鏈剖分,每條樹鏈用一個線段樹維護一下樹鏈上各個區間半平面交的結果,由於從祖先到子孫的dis[i]會遞增,所以我們有一個天然的斜率順序
所以這個可以用vector維護。
代碼:
因爲要會考就先咕了代碼叭QAQ
先弄個正確的代碼上來叭
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define ls x << 1
#define rs x << 1 | 1
#define eb emplace_back
#define pb pop_back
#define db double
const int MAX = 210033;
const ll inf = (1ll << 63) - 1;
struct Point
{
ll x, y;
Point() {}
Point(ll a, ll b) { x = a, y = b; }
friend Point operator - (Point a, Point b) { return Point(a.x - b.x, a.y - b.y); }
friend ll operator * (Point a, Point b) { return a.x * b.y - a.y * b.x; }
};
struct edge
{
int to; ll w;
edge() {}
edge(int a, ll b) { to = a, w = b; }
};
vector<edge> e[MAX];
vector<Point> h[MAX << 2];
int n, cnt_dfn;
int dfn[MAX], top[MAX], inv[MAX], siz[MAX], fa[MAX], que[MAX];
ll ans[MAX], P[MAX], Q[MAX], lim[MAX], dis[MAX];
void dfs1(int u)
{
siz[u] = 1;
for (auto v : e[u])
{
dis[v.to] = dis[u] + v.w;
dfs1(v.to);
siz[u] += siz[v.to];
}
}
void dfs2(int u, int tp)
{
int big = 0;
top[u] = tp, dfn[u] = ++cnt_dfn, inv[cnt_dfn] = u;
for (auto v : e[u])
if (siz[v.to] > siz[big])
big = v.to;
if (!big) return;
dfs2(big, tp);
for (auto v : e[u])
if (v.to != big)
dfs2(v.to, v.to);
}
void bfs()
{
int head, tail;
que[head = tail = 1] = 1;
while (head <= tail)
{
int u = que[head++];
for (auto v : e[u])
que[++tail] = v.to;
}
}
void update(int x, int l, int r, int p, Point c)
{
int siz = 0;
while ((siz = h[x].size()) > 1 && (c - h[x][siz - 2]) * (h[x][siz - 1] - h[x][siz - 2]) > 0)
h[x].pb();
h[x].eb(c);
if (l >= r) return;
int mid = (l + r) >> 1;
if (p <= mid) update(ls, l, mid, p, c);
else update(rs, mid + 1, r, p, c);
}
ll query(int x, int l, int r, int L, int R, int id)
{
ll Ans = inf;
if (L <= l && r <= R)
{
int lx = 0, rx = h[x].size() - 1;
while (rx - lx > 3)
{
int m1 = lx + (rx - lx) / 3, m2 = rx - (rx - lx) / 3;
ll v1 = P[id] * (dis[id] - h[x][m1].x) + h[x][m1].y;
ll v2 = P[id] * (dis[id] - h[x][m2].x) + h[x][m2].y;
if (v1 <= v2) rx = m2;
else lx = m1;
}
for (int i = lx; i <= rx; i++)
Ans = min(Ans, P[id] * (dis[id] - h[x][i].x) + h[x][i].y + Q[id]);
return Ans;
}
int mid = (l + r) >> 1;
if (L <= mid) Ans = min(Ans, query(ls, l, mid, L, R, id));
if (R > mid) Ans = min(Ans, query(rs, mid + 1, r, L, R, id));
return Ans;
}
void calc(int L, int R, int id)
{
ll Ans = inf;
while (dis[top[R]] > dis[L])
{
Ans = min(Ans, query(1, 1, n, dfn[top[R]], dfn[R], id));
R = fa[top[R]];
}
Ans = min(Ans, query(1, 1, n, dfn[L], dfn[R], id));
ans[id] = Ans;
update(1, 1, n, dfn[id], Point(dis[id], ans[id]));
}
main()
{
scanf("%lld%lld", &n, &fa[MAX - 1]);
for (int i = 2; i <= n; i++)
{
ll w;
scanf("%lld%lld%lld%lld%lld", &fa[i], &w, &P[i], &Q[i], &lim[i]);
e[fa[i]].eb(edge(i, w));
}
dfs1(1), dfs2(1, 1), bfs();
update(1, 1, n, 1, Point(0, 0));
for (int i = 2; i <= n; i++)
{
int anc = que[i], dist = dis[anc] - lim[anc];
anc = fa[anc];
while (anc > 1 && dis[fa[top[anc]]] >= dist)
anc = fa[top[anc]];
if (anc > 1)
{
int l = dfn[top[anc]], r = dfn[anc];
while (l <= r)
{
int mid = (l + r) >> 1;
if (dis[inv[mid]] >= dist)
anc = inv[mid], r = mid - 1;
else l = mid + 1;
}
}
else anc = 1;
calc(anc, fa[que[i]], que[i]);
}
for (int i = 2; i <= n; i++)
printf("%lld\n", ans[i]);
return 0;
}