P4069 [SDOI2016] 游戏 Solution
Description
给定一棵有 nnn 个点的树 TTT,点有点权 AiA_iAi,边有边权,初始时 wi=123456789123456789w_i=123456789123456789wi=123456789123456789.
定义 dist(s,t)\operatorname{dist}(s,t)dist(s,t) 为 s→ts\to ts→t 路径上边权之和,path(s,t)\operatorname{path}(s,t)path(s,t) 为 s→ts\to ts→t 路径上点集.
执行 qqq 次操作,操作分两种:
- modify(s,t,a,b)\operatorname{modify}(s,t,a,b)modify(s,t,a,b):对每个 u∈path(s,t)u\in \operatorname{path}(s,t)u∈path(s,t),执行 Au←min(Au,a×dist(s,u)+b)A_u\gets \min(A_u,a\times \operatorname{dist}(s,u)+b)Au←min(Au,a×dist(s,u)+b).
- query(s,t)\operatorname{query}(s,t)query(s,t):求 minu∈path(s,t)Ai\min\limits_{u\in\operatorname{path}(s,t)} A_iu∈path(s,t)minAi.
Limitations
1≤n,q≤1051\le n,q\le 10^51≤n,q≤105
∣a∣≤104,0≤w,∣b∣≤109|a|\le 10^4,0\le w,|b|\le 10^9∣a∣≤104,0≤w,∣b∣≤109
1s,250MB1\text{s},250\text{MB}1s,250MB
Solution
首先对 TTT 进行树链剖分.
注意到 y=a×dist(s,u)+by=a\times \operatorname{dist}(s,u)+by=a×dist(s,u)+b 是一次函数的形式,但 dist(s,u)\operatorname{dist}(s,u)dist(s,u) 随 sss 变化而变化,无法直接维护.
考虑从 lca\text{lca}lca 处断开,拆成两条垂直链 s→lcas\to\text{lca}s→lca 和 lca→t\text{lca}\to tlca→t,设 dep(u)\operatorname{dep}(u)dep(u) 为 uuu 的带权深度,对每条链分别考虑:
- 若 u∈path(s,lca)u\in\operatorname{path}(s,\text{lca})u∈path(s,lca) 则有 y=a×(dep(s)−dep(u))+b=−a×dep(u)+(a×dep(s)+b)y=a\times (\operatorname{dep}(s)-\operatorname{dep}(u))+b=-a\times \operatorname{dep}(u)+(a\times \operatorname{dep}(s) +b)y=a×(dep(s)−dep(u))+b=−a×dep(u)+(a×dep(s)+b).
- 若 u∈path(lca,t)u\in \operatorname{path}(\text{lca}, t)u∈path(lca,t) 则有 y=a×(dep(u)+dep(s)−2dep(lca))+b=a×dep(u)+(a×dep(s)+2a×dep(lca)+b)y=a\times (\operatorname{dep}(u)+\operatorname{dep}(s)-2\operatorname{dep}(\text{lca}))+b=a\times \operatorname{dep}(u)+(a\times \operatorname{dep}(s) +2a\times\operatorname{dep}(\text{lca})+b)y=a×(dep(u)+dep(s)−2dep(lca))+b=a×dep(u)+(a×dep(s)+2a×dep(lca)+b).
这两个都是关于 dep(u)\operatorname{dep}(u)dep(u) 的一次函数.
由于从上往下 dep(u)\operatorname{dep}(u)dep(u) 递增,直接用李超树维护,支持区间插入函数,求区间 miny\min yminy 的值.
注意到最值一定在两个端点处,于是做完了,时间复杂度 O(qlog3n)O(q\log^3 n)O(qlog3n),记得开 long long
.
Code
4.5KB,3.08s,31.55MB (C++20 with O2)4.5\text{KB},3.08\text{s},31.55\text{MB}\;\texttt{(C++20 with O2)}4.5KB,3.08s,31.55MB(C++20 with O2)
#include <bits/stdc++.h>
using namespace std;using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;template<class T>
bool chmax(T &a, const T &b){if(a < b){ a = b; return true; }return false;
}template<class T>
bool chmin(T &a, const T &b){if(a > b){ a = b; return true; }return false;
}constexpr i64 inf = 123456789123456789LL;struct line {i64 k, b;inline line() {}inline line(i64 k, i64 b) : k(k), b(b) {}
};inline int ls(int u) { return 2 * u + 1; }
inline int rs(int u) { return 2 * u + 2; }template<class F>
struct segtree {struct node {int l, r;i64 val;line f;};vector<node> tr;F func;inline segtree() {}inline segtree(int n, const F& f) : tr(n << 1), func(f) {build(0, 0, n - 1);}void build(int u, int l, int r) {tr[u].l = l, tr[u].r = r, tr[u].val = inf;tr[u].f = line(0, inf);if (l == r) return;const int mid = (l + r) >> 1;build(ls(mid), l, mid);build(rs(mid), mid + 1, r);}inline void pushup(int u, int mid) {chmin(tr[u].val, min(tr[ls(mid)].val, tr[rs(mid)].val));chmin(tr[u].val, min(func(tr[u].f, tr[u].l), func(tr[u].f, tr[u].r)));}void defeat(int u, line li) {const int mid = (tr[u].l + tr[u].r) >> 1;if (func(li, mid) < func(tr[u].f, mid)) swap(li, tr[u].f);if (tr[u].l == tr[u].r) {tr[u].val = min(tr[u].val, min(func(tr[u].f, tr[u].l), func(tr[u].f, tr[u].r)));return;}if (func(li, tr[u].l) < func(tr[u].f, tr[u].l)) defeat(ls(mid), li);if (func(li, tr[u].r) < func(tr[u].f, tr[u].r)) defeat(rs(mid), li);pushup(u, mid);}void update(int u, int l, int r, line li) {if (tr[u].r < l || r < tr[u].l) return;if (l <= tr[u].l && tr[u].r <= r) return defeat(u, li);const int mid = (tr[u].l + tr[u].r) >> 1;update(ls(mid), l, r, li);update(rs(mid), l, r, li);pushup(u, mid);}i64 query(int u, int l, int r) {if (tr[u].l > r || tr[u].r < l) return inf;if (l <= tr[u].l && tr[u].r <= r) return tr[u].val;const int mid = (tr[u].l + tr[u].r) >> 1;i64 ans = min(func(tr[u].f, max(l, tr[u].l)), func(tr[u].f, min(r, tr[u].r)));return min(ans, min(query(ls(mid), l, r), query(rs(mid), l, r)));}
};signed main() {ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n, q;cin >> n >> q;vector<vector<pair<int, int>>> g(n);for (int i = 0, u, v, w; i < n - 1; i++) {cin >> u >> v >> w, u--, v--;g[u].emplace_back(v, w);g[v].emplace_back(u, w);}vector<i64> dep(n);vector<int> par(n), siz(n), son(n, -1);auto dfs = [&](auto&& self, int u, int fa) -> void {siz[u] = 1, par[u] = fa;for (auto [v, w] : g[u]) {if (v == fa) continue;dep[v] = dep[u] + w;self(self, v, u);siz[u] += siz[v];if (son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v;}};int clock = 0;vector<int> dfn(n), top(n), rev(n);auto dfs2 = [&](auto&& self, int u, int topf) -> void {rev[dfn[u] = clock++] = u;top[u] = topf;if (~son[u]) self(self, son[u], topf);for (auto [v, w] : g[u]) {if (v == par[u] || v == son[u]) continue;self(self, v, v);}};dfs(dfs, 0, 0);dfs2(dfs2, 0, 0);auto func = [&](const line& li, int x) { return li.k * dep[rev[x]] + li.b; };segtree<decltype(func)> tree(n, func);auto lca = [&](int u, int v) {while (top[u] != top[v]) {if (dep[top[u]] < dep[top[v]]) swap(u, v);u = par[top[u]];}if (dep[u] > dep[v]) swap(u, v);return u;};auto upd = [&](int u, int v, line li) {while (top[u] != top[v]) {if (dep[top[u]] < dep[top[v]]) swap(u, v);tree.update(0, dfn[top[u]], dfn[u], li);u = par[top[u]];}if (dep[u] > dep[v]) swap(u, v);tree.update(0, dfn[u], dfn[v], li);};auto ask = [&](int u, int v) {i64 ans = inf;while (top[u] != top[v]) {if (dep[top[u]] < dep[top[v]]) swap(u, v);chmin(ans, tree.query(0, dfn[top[u]], dfn[u]));u = par[top[u]];}if (dep[u] > dep[v]) swap(u, v);chmin(ans, tree.query(0, dfn[u], dfn[v]));return ans;};auto modify = [&](int u, int v, int a, int b) {int lc = lca(u, v);upd(u, lc, line(-a, a * dep[u] + b));upd(lc, v, line(a, dep[u] * a - 2 * dep[lc] * a + b));};for (int i = 0, op, u, v, a, b; i < q; i++) {cin >> op >> u >> v, u--, v--;if (op == 1) cin >> a >> b, modify(u, v, a, b);else cout << ask(u, v) << '\n';}return 0;
}