SDOI2016 游戏
Day 4。
令 \(\text{lca}(u,v)=w\),\(s_u\) 为 \(u\) 到根的距离(随便指定一个根),考虑 \(u\to w\to v\) 的路径修改:
- \(x\in \{u\to w\}\):\(n_x\gets a(s_u-s_x)+b=-a\cdot s_x+(b+a\cdot s_u)\)。
- \(x\in \{w\to v\}\):\(n_x\gets a(s_u+s_x-2s_w)+b=a\cdot s_x+(a(s_u-2s_w)+b)\)。
考虑树链剖分,将修改拆分到 \(O(\log n)\) 条重链中。由于重链中 \(\text{id}\) 连续,这是关于 \(\text{id}(u)\) 的一次函数形式。李超线段树维护区间线段 \(\min\),在区间中插入线段即可。
李超树区间插入(非全局)是 \(O(\log^2n)\) 的(分成 \(O(\log n)\) 个区间后分别再在每个区间中插入),所以复杂度是 \(O(n\log^3n)\) 的。不知道为啥能过。
// Problem: #2032. 「SDOI2016」游戏
// Contest: LibreOJ
// URL: https://loj.ac/p/2032
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define int long long
using namespace std;
namespace vbzIO {
char ibuf[(1 << 20) + 1], *iS, *iT;
#if ONLINE_JUDGE
#define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, (1 << 20) + 1, stdin), (iS == iT ? EOF : *iS++) : *iS++)
#else
#define gh() getchar()
#endif
#define mt make_tuple
#define mp make_pair
#define fi first
#define se second
#define pc putchar
#define pb emplace_back
#define ins insert
#define era erase
typedef tuple<int, int, int> tu3;
typedef pair<int, int> pi;
inline int rd() {
char ch = gh();
int x = 0;
bool t = 0;
while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
return t ? ~(x - 1) : x;
}
inline void wr(int x) {
if (x < 0) x = ~(x - 1), putchar('-');
if (x > 9) wr(x / 10);
putchar(x % 10 + '0');
}
}
using namespace vbzIO;
const int N = 5e5 + 500;
const int inf = 123456789123456789;
int n, m, dfc, s[N];
int fa[N], sz[N], son[N], dep[N], top[N], id[N], pid[N], tr[N << 2], mn[N << 2];
vector<pi> g[N], p;
#define ls x << 1
#define rs x << 1 | 1
#define mid ((l + r) >> 1)
int cmp(int x, int y) { return (x == y ? 0 : (x > y ? 1 : -1)); }
int gety(int id, int x) { return p[id].fi * s[pid[x]] + p[id].se; }
void push(int l, int r, int s, int x) {
int &t = tr[x];
mn[x] = min(mn[x], min(gety(s, l), gety(s, r)));
if (cmp(gety(s, mid), gety(t, mid)) == -1) swap(s, t);
int fl = cmp(gety(s, l), gety(t, l)), fr = cmp(gety(s, r), gety(t, r));
if (fl == -1 || (!fl && s < t)) push(l, mid, s, ls);
if (fr == -1 || (!fr && s < t)) push(mid + 1, r, s, rs);
mn[x] = min(min(mn[ls], mn[rs]), mn[x]);
}
void upd(int l, int r, int s, int t, int id, int x) {
if (s <= l && r <= t) return push(l, r, id, x);
if (s <= mid) upd(l, mid, s, t, id, ls);
if (t > mid) upd(mid + 1, r, s, t, id, rs);
mn[x] = min(min(mn[ls], mn[rs]), mn[x]);
}
int qry(int l, int r, int s, int t, int x) {
if (s <= l && r <= t) return mn[x];
int res = min(gety(tr[x], max(l, s)), gety(tr[x], min(r, t)));
if (s <= mid) res = min(res, qry(l, mid, s, t, ls));
if (t > mid) res = min(res, qry(mid + 1, r, s, t, rs));
return res;
}
void dfs1(int u, int fat) {
fa[u] = fat, dep[u] = dep[fat] + 1, sz[u] = 1;
for (pi p : g[u]) {
int v = p.fi, w = p.se;
if (v == fat) continue;
s[v] = s[u] + w, dfs1(v, u), sz[u] += sz[v];
if (sz[v] > sz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int pre) {
top[u] = pre, pid[id[u] = ++dfc] = u;
if (son[u]) dfs2(son[u], pre);
for (pi p : g[u]) {
int v = p.fi;
if (v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
int lca(int u, int v) {
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
u = fa[top[u]];
}
return dep[u] < dep[v] ? u : v;
}
void upd(int u, int v, int i) {
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
upd(1, n, id[top[u]], id[u], i, 1), u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
upd(1, n, id[u], id[v], i, 1);
}
int qry(int u, int v) {
int res = inf;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
res = min(res, qry(1, n, id[top[u]], id[u], 1)), u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
return min(res, qry(1, n, id[u], id[v], 1));
}
signed main() {
n = rd(), m = rd();
for (int i = 1, u, v, w; i <= n - 1; i++)
u = rd(), v = rd(), w = rd(), g[u].pb(mp(v, w)), g[v].pb(mp(u, w));
p.pb(mp(0, inf));
dfs1(1, 0), dfs2(1, 1);
for (int i = 1; i < N << 2; i++) mn[i] = inf;
while (m--) {
int op = rd(), u = rd(), v = rd();
if (op == 1) {
int a = rd(), b = rd(), lc = lca(u, v);
p.pb(mp(-a, b + a * s[u])), upd(u, lc, p.size() - 1);
p.pb(mp(a, b - 2 * a * s[lc] + a * s[u])), upd(lc, v, p.size() - 1);
} else wr(qry(u, v)), pc('\n');
}
return 0;
}