harbingers 题解
该死,怎么这么强。
p r e [ i ] pre[i] pre[i] 表示 i i i 号点到根节点的距离,用的是手写栈。
d p [ i ] = d p [ j ] + s [ i ] + ( p r e [ i ] − p r e [ j ] ) ∗ v [ i ] d p [ i ] = d p [ j ] + s [ i ] + p r e [ i ] ∗ v [ i ] − p r e [ j ] ∗ v [ i ] − d p [ j ] = − p r e [ j ] ∗ v [ i ] + s [ i ] + p r e [ i ] ∗ v [ i ] − d p [ i ] d p [ j ] = p r e [ j ] ∗ v [ i ] − s [ i ] − p r e [ i ] ∗ v [ i ] + d p [ i ] y = d p [ j ] , k = v [ i ] , x = p r e [ j ] , b = d p [ i ] − s [ i ] − p r e [ i ] ∗ v [ i ] \begin{aligned}dp[i] = dp[j] + s[i] + (pre[i] - pre[j]) * v[i]\\dp[i] = dp[j] + s[i] + pre[i] * v[i] - pre[j] * v[i]\\-dp[j] = -pre[j] * v[i] + s[i] + pre[i] * v[i] - dp[i]\\dp[j] = pre[j] * v[i] - s[i] - pre[i] * v[i] + dp[i]\\y = dp[j], k = v[i], x = pre[j], b = dp[i] - s[i] - pre[i] * v[i]\end{aligned} dp[i]=dp[j]+s[i]+(pre[i]−pre[j])∗v[i]dp[i]=dp[j]+s[i]+pre[i]∗v[i]−pre[j]∗v[i]−dp[j]=−pre[j]∗v[i]+s[i]+pre[i]∗v[i]−dp[i]dp[j]=pre[j]∗v[i]−s[i]−pre[i]∗v[i]+dp[i]y=dp[j],k=v[i],x=pre[j],b=dp[i]−s[i]−pre[i]∗v[i]
d p [ i ] dp[i] dp[i] 的符号为正,所以是下凸包, v [ i ] v[i] v[i] 没有单调性,所以只能是二分查找。
y e e yee yee 就是说,假设我们现在转移节点 i i i,那么 j j j 的取值就是 i i i 到根节点的路径上的所有点。
由于回溯将弹掉的决策一个个的加上,时间复杂度炸飞,所以我们考虑优化。
我们发现保存的决策是一个栈栈结构,只在末尾进进出出,所以删除的决策一定是栈中的一段连续区间。
那就太好了,我们把删除栈的一段区间改为:
- 1.二分找到删除区间的第一个元素: l l l。
- 2.将栈顶指针指向 l l l
- 3.将 s t a c k [ l ] stack[l] stack[l] 修改为新加入元素 i i i。
- 4.递归结束后,将 s t a c k [ l ] stack[l] stack[l] 改为原来的值,然后将栈顶指针指向原来的位置。
这样魔改了弹栈操作后,时间复杂度就满足要求了( O ( n ⋅ l o g 2 n ) O (n \cdot log_2n) O(n⋅log2n))。
//author : LH ——Who just can eat S??t
//worship WJC ——Who can f??k tourist up and down and loves 周歆恬
//worship YJX ——Who can f??k WJC up and down
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define fi first
#define se second
#define db double
#define LL __int128
#define ULL unsigned long long
#define PII pair <int, int>
#define MP(x,y) make_pair (x, y)
#define rep(i,j,k) for (int i = (j); i <= (k); ++i)
#define per(i,j,k) for (int i = (j); i >= (k); --i)
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }
template <typename T>
void read (T &x) {
x = 0; T f = 1;
char ch = getchar ();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar ();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + ch - '0';
ch = getchar ();
}
x *= f;
}
template <typename T, typename... Args>
void read (T &x, Args&... args) {
read (x); read (args...);
}
char For_Print[25];
template <typename T>
void write (T x) {
if (x == 0) { putchar ('0'); return; }
if (x < 0) { putchar ('-'); x = -x; }
int poi = 0;
while (x) {
For_Print[++poi] = x % 10 + '0';
x /= 10;
}
while (poi) putchar (For_Print[poi--]);
}
template <typename T>
void print (T x, char ch) {
write (x); putchar (ch);
}
const int Maxn = 1e5;
int n;
struct Postman {
LL s, v;
} a[Maxn + 5];
struct edge {
int len, Head[Maxn + 5];
int to[Maxn * 2 + 5], Next[Maxn * 2 + 5]; LL val[Maxn * 2 + 5];
void add (int u, int v, LL _val) {
to[++len] = v;
val[len] = _val;
Next[len] = Head[u];
Head[u] = len;
}
}mp;
LL pre[Maxn + 5], dp[Maxn + 5];
int st[Maxn + 5], tp;
db X (int j) {
return pre[j];
}
db Y (int j) {
return dp[j];
}
db DX (int k, int j) {
return X (j) - X (k);
}
db DY (int k, int j) {
return Y (j) - Y (k);
}
int Get_Idx (int i) {
if (tp == 0) return 1;
int l = 1, r = tp + 1;
while (l + 1 < r) {
int mid = (l + r) >> 1;
if (DY (st[mid - 1], st[mid]) / DX (st[mid - 1], st[mid]) >= DY (st[mid], i) / DX (st[mid], i))
r = mid;
else
l = mid;
}
return l + 1;
}
LL Get_Val (int j, int i) {
return dp[j] + a[i].s + (pre[i] - pre[j]) * a[i].v;
}
LL Get_Dp (int i) {
int l = 1, r = tp + 1;
while (l + 1 < r) {
int mid = (l + r) >> 1;
if (DY (st[mid - 1], st[mid]) / DX (st[mid - 1], st[mid]) <= a[i].v) l = mid;
else r = mid;
}
return Get_Val (st[l], i);
}
void Tree (int u, int _fa) {
int idx = Get_Idx (u), backup_val = st[idx], backup_tp = tp;
st[idx] = u; tp = idx;
for (int i = mp.Head[u]; i; i = mp.Next[i]) {
int v = mp.to[i]; LL _val = mp.val[i];
if (v == _fa) continue;
pre[v] = pre[u] + _val;
dp[v] = Get_Dp (v);
Tree (v, u);
}
st[idx] = backup_val; tp = backup_tp;
}
int main () {
// freopen ("1.in", "r", stdin);
// freopen ("1.out", "w", stdout);
read (n);
rep (i, 1, n - 1) {
int x, y, _val; read (x, y, _val);
mp.add (x, y, _val); mp.add (y, x, _val);
}
rep (i, 2, n) {
read (a[i].s, a[i].v);
}
Tree (1, -1);
rep (i, 2, n) {
print (dp[i], ' ');
}
return 0;
}