题目链接:点我啊╭(╯^╰)╮
题目大意:
从城市
i
i
i 到城市
j
j
j 的代价为
d
∗
p
i
+
q
i
d*p_i+q_i
d∗pi+qi
d
d
d 为距离,且
j
j
j 为
i
i
i 的祖先节点
每个城市有一个限制
l
i
l_i
li,表示一次购票距离的上限
求每个城市到根节点的最少代价
解题思路:
d
p
[
i
]
=
m
i
n
(
d
p
[
j
]
+
(
d
i
s
i
−
d
i
s
j
)
∗
p
i
+
q
i
)
dp[i] = min(dp[j] + (dis_i - dis_j) * p_i + q_i)
dp[i]=min(dp[j]+(disi−disj)∗pi+qi)
j
j
j 为
i
i
i 的祖先节点,
d
i
s
dis
dis 为到根节点的距离
很明显具有斜率优化的性质,维护上凸包,
p
i
p_i
pi 不单调,需要二分
关键在于这是一棵树,需要用点分治处理
第三步按照
d
i
s
i
−
l
i
dis_i - l_i
disi−li 排序,大的排在前面,因为要淘汰
将祖先节点放在
A
A
A 里,排序后的子节点放在
B
B
B 里
对于
B
B
B 而言,答案就可以在
A
A
A 里斜率
d
p
dp
dp
+
+
+ 二分处理
注意枚举
B
B
B 的时候,要确保可能的
A
A
A 都已经遍历到了
最后二分结果要
+
1
+1
+1,才是最优节点,并且队尾的斜率为
−
∞
-∞
−∞
找重心有一个特殊情况:两个点的重心必须是父亲节点!
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const int maxn = 2e5 + 5;
int n, m, t, f[maxn], hvy, mxp, sz[maxn];
int rt, an, bn, A[maxn], B[maxn], vis[maxn], Q[maxn];
ll p[maxn], q[maxn], l[maxn], dp[maxn], dis[maxn], s[maxn];
vector <int> g[maxn];
double sl[maxn];
void getdis(int u){
for(auto v : g[u]){
dis[v] = dis[u] + s[v];
getdis(v);
}
}
void gethvy(int u){
sz[u] = 1; int tmxp = 0;
for(auto v : g[u]){
if(vis[v]) continue;
gethvy(v);
sz[u] += sz[v];
tmxp = max(tmxp, sz[v]);
}
tmxp = max(tmxp, m - sz[u]);
if(tmxp <= mxp){ // 注意少了 = 会死循环
mxp = tmxp;
hvy = u;
}
}
void dfs(int u){
B[++bn] = u;
for(auto v : g[u]){
if(vis[v]) continue;
dfs(v);
}
}
bool cmp(int ca, int cb){
return dis[ca] - l[ca] > dis[cb] - l[cb];
}
double slope(int i, int j){
return 1.0 * (dp[i] - dp[j]) / (dis[i] - dis[j]);
}
void solve(int H){
if(m <= 1) return;
mxp = m, hvy = H;
gethvy(H); int nhvy = hvy;
for(auto v : g[hvy]) vis[v] = 1, m -= sz[v];
solve(H); hvy = nhvy;
rt = hvy, an = 0, bn = 0;
while(rt ^ H) A[++an] = rt, rt = f[rt];
A[++an] = H;
for(auto v : g[hvy]) dfs(v);
sort(B+1, B+1+bn, cmp);
int tail = 0, bi = 1;
while(bi<=bn && dis[B[bi]]-l[B[bi]]>dis[hvy]) bi++;
for(int i=1; i<=an; i++){
while(tail>1 && sl[tail-1]<=slope(Q[tail], A[i])) tail--;
Q[++tail] = A[i], sl[tail] = -1e18, sl[tail-1] = slope(Q[tail-1], Q[tail]);
while(bi<=bn && (i==an || dis[B[bi]]-l[B[bi]]>dis[A[i+1]])){
int L = 1, R = tail, mid;
while(L <= R){
mid = L + R >> 1;
if(sl[mid] >= p[B[bi]]) L = mid + 1;
else R = mid - 1;
}
int ti = B[bi], tj = Q[R+1]; // R + 1 == L
dp[ti] = min(dp[ti], dp[tj] + p[ti] * (dis[ti] - dis[tj]) + q[ti]);
bi++;
}
}
for(auto v : g[hvy]) m = sz[v], solve(v);
}
signed main() {
scanf("%d%d", &n, &t);
for(int i=2; i<=n; i++){
scanf("%d%lld%lld%lld%lld", f+i, s+i, p+i, q+i, l+i);
g[f[i]].push_back(i);
dp[i] = 1e18;
}
getdis(1);
m = n;
solve(1);
for(int i=2; i<=n; i++) printf("%lld\n", dp[i]);
}