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(nlog2n))。

//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;
}
posted @ 2022-02-09 16:23  C2022lihan  阅读(14)  评论(0编辑  收藏  举报