当前位置: 首页 > news >正文

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 tst 路径上边权之和,path⁡(s,t)\operatorname{path}(s,t)path(s,t)s→ts\to tst 路径上点集.

执行 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)upath(s,t),执行 Au←min⁡(Au,a×dist⁡(s,u)+b)A_u\gets \min(A_u,a\times \operatorname{dist}(s,u)+b)Aumin(Au,a×dist(s,u)+b).
  • query⁡(s,t)\operatorname{query}(s,t)query(s,t):求 min⁡u∈path⁡(s,t)Ai\min\limits_{u\in\operatorname{path}(s,t)} A_iupath(s,t)minAi.

Limitations

1≤n,q≤1051\le n,q\le 10^51n,q105
∣a∣≤104,0≤w,∣b∣≤109|a|\le 10^4,0\le w,|b|\le 10^9a104,0w,b109
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}slcalca→t\text{lca}\to tlcat,设 dep⁡(u)\operatorname{dep}(u)dep(u)uuu 的带权深度,对每条链分别考虑:

  • u∈path⁡(s,lca)u\in\operatorname{path}(s,\text{lca})upath(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)upath(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) 递增,直接用李超树维护,支持区间插入函数,求区间 min⁡y\min yminy 的值.
注意到最值一定在两个端点处,于是做完了,时间复杂度 O(qlog⁡3n)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;
}
http://www.dtcms.com/a/333646.html

相关文章:

  • “社保新规”9月施行,内容、影响与时代意义
  • Ansible 学习笔记:变量事实管理、任务控制与文件部署
  • 分布式锁的具体实现和原理分析
  • 无线收发模块高效协同:EMS系统监控、交互、执行端同步通讯
  • SpringCloud学习
  • 现金流分析与预测提示词设计指南:从基础到复杂场景的实用框架
  • IO多路复用底层原理
  • Python中推导式和表达式
  • 基本电子元件:碳膜电阻器
  • 代码随想录二刷之“字符串”~GO
  • 集合车位租售、充电桩共享、二手市场、便民服务的家政服务平台,带源码
  • 数说故事发布全新AI产品:Social Research,免费洞察各行各业趋势,提升营销效率
  • 20250815日记
  • 智慧零碳园区——解读2025 零碳产业园区实施路径规划【附全文阅读】
  • pytorch学习笔记-模型的保存与加载(自定义模型、网络模型)
  • 大白话解析 Solidity 中的防重放参数
  • USENIX Security ‘24 Fall Accepted Papers (1)
  • 归并排序和统计排序
  • 用matlab实现的svdd算法
  • 2025年机械制造、机器人与计算机工程国际会议(MMRCE 2025)
  • gnu arm toolchain中的arm-none-eabi-gdb.exe的使用方法?
  • C#WPF实战出真汁05--左侧导航
  • 日常反思总结
  • 异步开发:协程、线程、Unitask
  • 线性代数 · 直观理解矩阵 | 空间变换 / 特征值 / 特征向量
  • 树莓派开机音乐
  • 模板引用(Template Refs)全解析2
  • CVE-2025-8088复现
  • 汽车行业 AI 视觉检测方案(二):守护车身密封质量
  • 【总结】Python多线程