题解:P11343 [KTSC 2023 R1] 出租车旅行
经过路径中除了终点外,其他点的
按照
这个 DP 直接点分树每个点维护子树的动态开点李超树就行。由于这里加入的直线是全局加入,所以李超树是一个
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int N = 1e5 + 5, M = 1e7 + 5;
std::vector<long long> travel(std::vector<long long> A, std::vector<int> B, std::vector<int> U, std::vector<int> V, std::vector<int> W);
int n, wc, tot;
array<ll, N> a, b, ans;
array<vector<pair<int, ll>>, N> G;
array<vector<int>, N> NG;
array<array<int, 20>, N> faf;
array<int, N> dep, sz, vis, dfa;
array<ll, N> dist, f;
void dfs(int u, int fa)
{
faf[u][0] = fa;
dep[u] = dep[fa] + 1;
for (auto &[j, w] : G[u])
{
if (j ^ fa) dist[j] = dist[u] + w, dfs(j, u);
}
}
inline int LCA(int u, int v)
{
if (dep[u] < dep[v]) swap(u, v);
int k = dep[u] - dep[v], c = 0;
while (k)
{
if (k & 1) u = faf[u][c];
k >>= 1;
c++;
}
if (u == v) return u;
for (int i = 19; i >= 0; i--) if (faf[u][i] ^ faf[v][i]) u = faf[u][i], v = faf[v][i];
return faf[u][0];
}
inline ll qdis(int u, int v){return dist[u] + dist[v] - 2ll * dist[LCA(u, v)];}
inline void dfs2(int u, int fa)
{
sz[u] = 0;
if (vis[u]) return;
sz[u] = 1;
for (auto &[j, w] : G[u])
{
if (j ^ fa)
{
dfs2(j, u);
sz[u] += sz[j];
}
}
}
inline void dfs3(int u, int fa)
{
if (vis[u]) return;
int maxn = tot - sz[u];
for (auto &[j, w] : G[u])
{
if (j == fa) continue;
dfs3(j, u);
maxn = max(maxn, sz[j]);
}
if (maxn <= (tot >> 1)) wc = u;
}
inline void dc(int u, int fav)
{
if (vis[u]) return;
dfs2(u, 0);
tot = sz[u];
dfs3(u, 0);
u = wc;
vis[u] = 1;
if (~fav) NG[fav].emplace_back(u), dfa[u] = fav;
for (auto &[j, w] : G[u]) dc(j, u);
}
class Lichao_SegmentTree
{
public:
int idx;
struct Node
{
int ls, rs;
ll k, b; // kx + b
Node()
{
ls = rs = k = 0, b = (ll)3e18;
}
};
array<Node, M> tr;
inline void crt(int u)
{
if (!tr[u].ls) tr[u].ls = ++idx;
if (!tr[u].rs) tr[u].rs = ++idx;
}
inline ll qry(ll k, ll b, ll x)
{
return k * x + b;
}
inline void pushtag(int u, ll l, ll r, ll k, ll b)
{
ll mid = l + r >> 1;
if (qry(k, b, l) <= qry(tr[u].k, tr[u].b, l) && qry(k, b, r) <= qry(tr[u].k, tr[u].b, r))
{
tr[u].k = k, tr[u].b = b;
return;
}
else if (qry(k, b, l) >= qry(tr[u].k, tr[u].b, l) && qry(k, b, r) >= qry(tr[u].k, tr[u].b, r)) return;
if (qry(k, b, mid) < qry(tr[u].k, tr[u].b, mid))
{
swap(k, tr[u].k);
swap(b, tr[u].b);
crt(u);
if (qry(k, b, r) < qry(tr[u].k, tr[u].b, r)) pushtag(tr[u].rs, mid + 1, r, k, b);
if (qry(k, b, l) < qry(tr[u].k, tr[u].b, l)) pushtag(tr[u].ls, l, mid, k, b);
}
else
{
crt(u);
if (qry(k, b, r) < qry(tr[u].k, tr[u].b, r)) pushtag(tr[u].rs, mid + 1, r, k, b);
if (qry(k, b, l) < qry(tr[u].k, tr[u].b, l)) pushtag(tr[u].ls, l, mid, k, b);
}
}
inline void ins(int& u, ll k, ll b)
{
if (!u) u = ++idx;
pushtag(u, 1ll, (ll)1e11, k, b);
}
inline ll query(int u, ll l, ll r, ll x)
{
if (!u) return (ll)3e18;
ll res = qry(tr[u].k, tr[u].b, x);
if (l == r) return res;
ll mid = l + r >> 1;
if (x <= mid) res = min(res, query(tr[u].ls, l, mid, x));
else res = min(res, query(tr[u].rs, mid + 1, r, x));
return res;
}
}sgt;
array<int, N> rt, p;
inline void upd(int u, ll val)
{
f[u] = val;
for (int x = u; x; x = dfa[x])
{
sgt.ins(rt[x], b[u], f[u] + a[u] + qdis(u, x) * b[u]);
}
}
inline ll query(int u)
{
ll res = (ll)3e18;
for (int x = u; x; x = dfa[x]) res = min(res, sgt.query(rt[x], 1, (ll)1e11, qdis(u, x)));
return res;
}
std::vector<long long> travel(std::vector<long long> A, std::vector<int> B, std::vector<int> U, std::vector<int> V, std::vector<int> W)
{
n = A.size();
for (int i = 1; i <= n; i++) a[i] = A[i - 1], b[i] = B[i - 1];
for (int i = 0; i < n - 1; i++)
{
G[U[i] + 1].emplace_back(V[i] + 1, W[i]);
G[V[i] + 1].emplace_back(U[i] + 1, W[i]);
}
dfs(1, 0);
for (int j = 1; j < 20; j++) for (int i = 1; i <= n; i++) faf[i][j] = faf[faf[i][j - 1]][j - 1];
dc(1, -1);
for (int i = 1; i <= n; i++) p[i] = i, f[i] = (ll)3e18;
upd(1, 0);
sort(p.begin() + 1, p.begin() + n + 1, [&](const int& x, const int& y){return b[x] > b[y];});
for (int i = 1; i <= n; i++)
{
int j = p[i];
if (j != 1) upd(j, query(j));
}
vector<ll> ret;
for (int i = 2; i <= n; i++)
{
ans[i] = min(f[i], query(i));
ret.emplace_back(ans[i]);
}
return ret;
}