当前位置: 首页 > 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.xdnf.cn/news/1302751.html

相关文章:

  • 微信小程序 拖拽签章
  • Git版本控制器
  • spring中异步任务注解@Async和@scheduled的使用
  • 2025年机械制造、机器人与计算机工程国际会议(MMRCE 2025)
  • Docker Compose 入门教程
  • MySQL、PolarDB、PolarDB-X、TableStore、MongoDB、TiDB、ClickHouse选型
  • docker入门
  • Java 调用 Python 脚本:实现 HelloWorld
  • 计算机视觉(opencv)实战五——图像平滑处理(均值滤波、方框滤波、高斯滤波、中值滤波)附加:视频逐帧平滑处理
  • 从根本上解决MAC权限问题(关闭sip)
  • SSL和TLS协议的消息认证码(MAC)
  • Android RxJava变换操作符详解
  • 使用SQLALCHEMY的outerjoin时的bug
  • 训练大模型的前提:数据治理工程:从原始数据到高质量语料的系统化治理实践
  • vector接口模拟实现及其原理
  • Redis 官方提供免费的 30 MB 云数据库
  • 阿里云出里两款新的云服务器
  • Uniapp之微信小程序自定义底部导航栏形态
  • 订单簿数据智能解析深度学习算法筛选大单并预测即时价格变动
  • MuMu模拟器Pro Mac 安卓手机平板模拟器(Mac中文)
  • 智能家居【home assistant】(二)-集成xiaomi_home
  • 云原生俱乐部-k8s知识点归纳(3)
  • 【计算机视觉与深度学习实战】02基于形态学的权重自适应图像去噪系统
  • 自学大语言模型之Transformer的Tokenizer
  • Android 欧盟网络安全EN18031 要求对应的基本表格填写
  • 对抗损失(GAN)【生成器+判断器】
  • HarmonyOS 实战:用 List 与 AlphabetIndexer 打造高效城市选择功能
  • 【Java】HashMap的详细介绍
  • PCA降维全解析:从原理到实战
  • JAVA文件管理系统:如何玩转文件操作