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;
}
5452

被折叠的 条评论
为什么被折叠?



