【题解】可持久化区间仿射区间和(Persistent Range Affine Range Sum)
很好小朋友们我们被要求写一个可持久化线段树支持区间修改、区间复制和输出区间和。懒标记是必须的但可持久化线段树一般不太支持 pushdown尤其在本题中。在进入子节点之前我们需要克隆当前节点因为当前节点可能被其他版本共享。然后才能将其懒标记下推到新克隆出的子节点最后将当前节点的懒标记重置。这样会导致不必要的新节点开销。于是我们不考虑 pushdown而是在递归函数中同时传进祖先变化即懒标记。线段树维护五个参数分别是左右子节点、区间总和 b、c 懒标记。1处理操作 0我们构建一个 change 函数对版本 p 的区间 [l, r] 施加变换 x - b*x c返回新版本的根节点。可持久化的精髓是“改了才新建”编写时请注意祖先变化的传递。2处理操作 1一个个复制绝对是不明智的我们可以先构建一个 crossover 函数。合并两个版本 x 和 y返回一个新版本其前 at 个元素来自 x后 len - at 个元素来自 y。这样题目的 [l, r] 可以变成先处理 [1, r] 的复制接着把原来的 [1, l - 1] 复制回去。3处理操作 2正常的 query 函数即可。另注意本题的边界和 base 十分复杂我用的是统一 base-1。#include bits/stdc.h using namespace std; typedef long long LL; const LL P 998244353; // 模数 const int N 1e5 10; // 数组最大长度 #define lc(p) tr[p].lc // 左孩子下标 #define rc(p) tr[p].rc // 右孩子下标 #define MID ((L R) 1) // 当前区间中点 /* 线段树节点结构 lc, rc : 左右孩子指针下标 sum : 当前节点代表的区间和已应用该节点的懒标记 lazy_b, lazy_c : 懒标记表示对子区间施加的仿射变换 x - lazy_b * x lazy_c */ struct node { int lc, rc; LL sum; LL lazy_b, lazy_c; }; vectornode tr; // 动态存储所有节点0 号节点为空节点 LL a[N]; // 原始数组1‑based // 新建一个节点懒标记初始为恒等变换 (1, 0) int newd() { tr.push_back({0, 0, 0, 1, 0}); return (int)tr.size() - 1; } // 克隆节点 p复制其所有信息 int clone_node(int p) { tr.push_back(tr[p]); return (int)tr.size() - 1; } /* 将仿射变换 x - b*x c 应用到节点 p 所代表的整个区间长度为 len 同时更新该节点的懒标记使其与原有懒标记复合。 注意应用顺序为 新变换 作用于 旧变换即最终变换为 b*(old(x)) c。 */ void modify(int p, LL b, LL c, LL len) { if (p 0) return; tr[p].sum (b * tr[p].sum c * len) % P; tr[p].lazy_b b * tr[p].lazy_b % P; tr[p].lazy_c (b * tr[p].lazy_c % P c) % P; } // 复合变换返回 g(f())即先 f 后 g pairLL, LL compose(LL g_b, LL g_c, LL f_b, LL f_c) { return { (g_b * f_b) % P, (g_b * f_c g_c) % P }; } // 用左右子树的 sum 更新当前节点的 sum void pushup(int p) { tr[p].sum (tr[lc(p)].sum tr[rc(p)].sum) % P; } // 建树p 为引用返回根节点下标 void build(int p, int L, int R) { p newd(); if (L R) { tr[p].sum a[L] % P; return; } build(lc(p), L, MID); build(rc(p), MID 1, R); pushup(p); } /* 对版本 p 的区间 [l, r] 施加变换 x - b*x c返回新版本的根节点。 参数 prop_b, prop_c 表示从根到当前节点路径上所有祖先懒标记复合后的变换 需要在访问当前区间时应用。 本函数采用路径复制只修改必要的节点保留未修改部分。 */ int change(int p, int L, int R, int l, int r, LL b, LL c, LL prop_b, LL prop_c) { // 完全不相交克隆当前节点并应用祖先变换然后返回 if (r L || R l) { int np clone_node(p); modify(np, prop_b, prop_c, R - L 1); return np; } // 完全覆盖克隆当前节点整体施加 “祖先变换 当前变换” if (l L R r) { auto t compose(b, c, prop_b, prop_c); // 先 prop后 (b,c) int np clone_node(p); modify(np, t.first, t.second, R - L 1); return np; } // 部分重叠创建新节点懒标记为恒等 int np newd(); // 传递给子节点的祖先变换 prop ∘ p.lazy先 p.lazy后 prop auto t compose(prop_b, prop_c, tr[p].lazy_b, tr[p].lazy_c); // 左子区间有重叠递归处理 if (l MID) { lc(np) change(lc(p), L, MID, l, r, b, c, t.first, t.second); } else { // 左子区间没有重叠克隆并应用祖先变换 if (lc(p) ! 0) { int lc clone_node(lc(p)); modify(lc, t.first, t.second, MID - L 1); lc(np) lc; } } // 右子区间有重叠递归处理 if (r MID 1) { rc(np) change(rc(p), MID 1, R, l, r, b, c, t.first, t.second); } else { if (rc(p) ! 0) { int rc clone_node(rc(p)); modify(rc, t.first, t.second, R - (MID 1) 1); rc(np) rc; } } pushup(np); return np; } // 封装 update - change初始祖先变换为恒等 int update(int p, int L, int R, int l, int r, LL b, LL c) { return change(p, L, R, l, r, b, c, 1, 0); } /* 合并两个版本 x 和 y返回一个新版本其前 at 个元素来自 x后 len - at 个元素来自 y。 参数 xb,xc 和 yb,yc 分别为两个版本当前需要应用的祖先变换。 具体规则 - at 0 全部取 y - at len 全部取 x - 否则根据 at 与左子树长度的关系递归处理左右子树。 */ int crossover(int x, int y, int len, int at, LL xb, LL xc, LL yb, LL yc) { if (at 0) { // 全部来自 y if (y 0) return 0; int ny clone_node(y); modify(ny, yb, yc, len); return ny; } if (len at) { // 全部来自 x if (x 0) return 0; int nx clone_node(x); modify(nx, xb, xc, len); return nx; } int midl (len 1) 1; // 左子树长度尽量平衡 // 为啥是上取整len R - L 1 // MID (R L) / 2 // midl MID - L 1 // 2 * midl R L - 2 * L 2 * 1 // midl R - L 1 LL nx_b, nx_c, ny_b, ny_c; // 将 x 的祖先变换与其自身懒标记复合得到传递给左/右子树的变换 if (x ! 0) { auto res compose(xb, xc, tr[x].lazy_b, tr[x].lazy_c); nx_b res.first; nx_c res.second; } else { nx_b xb; nx_c xc; } if (y ! 0) { auto res compose(yb, yc, tr[y].lazy_b, tr[y].lazy_c); ny_b res.first; ny_c res.second; } else { ny_b yb; ny_c yc; } int left_x (x 0) ? 0 : lc(x); int left_y (y 0) ? 0 : lc(y); int right_x (x 0) ? 0 : rc(x); int right_y (y 0) ? 0 : rc(y); // 左子树需要的前 at 个元素来自 x int lc crossover(left_x, left_y, midl, at, nx_b, nx_c, ny_b, ny_c); // 右子树需要的前 at - midl 个元素来自 x int rc crossover(right_x, right_y, len - midl, at - midl, nx_b, nx_c, ny_b, ny_c); int res newd(); lc(res) lc; rc(res) rc; pushup(res); return res; } /* 操作 1 的封装将版本 y 的区间 [l, r] 复制到版本 x 的对应位置。 通过两次交叉实现 1. tmp x[0 : l - 1] y[l : n] 2. 结果 tmp[0 : r] x[r : n] x[0 : l - 1] y[l : r] x[r : n] */ int update_crossover_twice(int x, int y, int l, int r, int total_len) { int tmp crossover(x, y, total_len, l - 1, 1, 0, 1, 0); return crossover(tmp, x, total_len, r, 1, 0, 1, 0); } /* 查询版本 p 中区间 [l, r] 的和。 参数 b, c 表示当前路径上所有祖先懒标记复合后的变换 在完全覆盖时直接应用到当前节点的 sum 上。 */ LL query(int p, int L, int R, int l, int r, LL b, LL c) { if (r L || R l) { return 0; } if (l L R r) { return (b * tr[p].sum c * (R - L 1)) % P; } // 传递给子节点的祖先变换 (b,c) ∘ p.lazy先 p.lazy后当前祖先 auto t compose(b, c, tr[p].lazy_b, tr[p].lazy_c); LL res 0; res query(lc(p), L, MID, l, r, t.first, t.second); res query(rc(p), MID 1, R, l, r, t.first, t.second); return res % P; } int main() { ios::sync_with_stdio(false); cin.tie(0); int n, Q; cin n Q; for (int i 1; i n; i ) cin a[i]; tr.reserve(20000000); // 预留节点空间 tr.push_back({0, 0, 0, 1, 0}); // 0 号节点作为空节点 int rt; build(rt, 1, n); vectorint roots(Q 1); // roots[i] 存储版本 A_i 的根节点 roots[0] rt; // 初始版本 A_{-1} for (int i 1; i Q; i) { int opt; cin opt; // 输入中 k, s 为 0‑based 版本编号-1 表示初始版本所以用 k1 索引 roots if (opt 0) { // 区间仿射变换 int k, l, r; LL b, c; cin k l r b c; l ; // 输入区间为 [l, r) 的 0‑based 下标转为 1‑based int src roots[k 1]; roots[i] update(src, 1, n, l, r, b, c); } else if (opt 1) { // 区间从另一版本复制 int k, s, l, r; cin k s l r; l ; int src_k roots[k 1]; int src_s roots[s 1]; roots[i] update_crossover_twice(src_k, src_s, l, r, n); } else { // 区间求和查询 int k, l, r; cin k l r; l ; int src roots[k 1]; cout query(src, 1, n, l, r, 1, 0) \n; roots[i] roots[i - 1]; } } return 0; }

相关新闻

告别手速焦虑:5分钟掌握大麦抢票脚本终极指南

告别手速焦虑:5分钟掌握大麦抢票脚本终极指南

告别手速焦虑:5分钟掌握大麦抢票脚本终极指南 【免费下载链接】DamaiHelper 大麦网演唱会演出抢票脚本。 项目地址: https://gitcode.com/gh_mirrors/dama/DamaiHelper 还在为抢不到心仪演唱会门票而烦恼吗?DamaiHelper是一个基于Python和Seleniu…

2026/10/10 19:16:45 阅读更多 →
ProxySQL源码编译常见问题与解决方案

ProxySQL源码编译常见问题与解决方案

1. ProxySQL编译报错问题解析 最近在尝试从源码编译ProxySQL时遇到了几个典型的编译错误。作为一款高性能的MySQL中间件,ProxySQL的编译过程确实比普通应用要复杂一些,特别是当开发环境配置不完整时,各种依赖问题就会接踵而至。下面我将分享几…

2026/10/2 7:20:59 阅读更多 →
mcp-gsc安全最佳实践:保护你的GSC数据和API凭证

mcp-gsc安全最佳实践:保护你的GSC数据和API凭证

mcp-gsc安全最佳实践:保护你的GSC数据和API凭证 【免费下载链接】mcp-gsc Google Search Console Insights with Claude AI for SEOs 项目地址: https://gitcode.com/gh_mirrors/mc/mcp-gsc mcp-gsc作为一款结合Google Search Console Insights与Claude AI的…

2026/9/25 22:53:16 阅读更多 →

最新新闻

多模态视觉+云端真机:AI助手从聊天框到实操代理的落地实践

多模态视觉+云端真机:AI助手从聊天框到实操代理的落地实践

1. 从"聊天框套壳"说起:为什么大多数AI助手止步于对话框过去两年,我接触过不下三十个号称"AI助手"的项目,其中绝大多数打开之后就是一个输入框加一个发送按钮,背后调一个通用大模型的API,再套一层…

2026/10/14 15:10:52 阅读更多 →
如何让AI Agent自动下载Spotify歌单:Sunnify的NDJSON事件流与doctor自检完整指南

如何让AI Agent自动下载Spotify歌单:Sunnify的NDJSON事件流与doctor自检完整指南

【免费下载链接】sunnify-spotify-downloader Sunnify is a Spotify downloader application CLI that allows you to download entire playlists locally onto your Mac/Linux/Windows PC. 项目地址: https://gitcode.com/gh_mirrors/su/sunnify-spotify-download…

2026/10/14 15:10:52 阅读更多 →
软件工程过程资产包:23类可执行文档模板与自动化工具

软件工程过程资产包:23类可执行文档模板与自动化工具

简介:本资源是面向软件工程专业学生、初入行的开发工程师及项目管理学习者的全流程文档实践包,聚焦课程设计与真实项目交付中必需的标准化文档体系。压缩包共141个文件,涵盖需求分析.doc、概要设计说明书.doc、详细设计说明.doc、用户手册.do…

2026/10/14 15:10:52 阅读更多 →
KaKs_Calculator 2.0 实战指南:从密码子比对到选择压力分析

KaKs_Calculator 2.0 实战指南:从密码子比对到选择压力分析

简介:KaKs_Calculator 2.0 是一款面向生物信息学研究者的开源工具包,用于估算非同义替代率(Ka)与同义替代率(Ks),进而衡量基因编码序列受到的选择压力。软件融合伽马级数方法与滑动窗口策略&…

2026/10/14 15:10:52 阅读更多 →
H5商城.zip:轻量级电商前端骨架与工程实践指南

H5商城.zip:轻量级电商前端骨架与工程实践指南

简介:这是一套高仿必要APP的H5手机端商城静态页面资源,面向前端初学者与求职者,用于快速掌握移动端商城核心功能模块的HTMLCSSJS实现逻辑。资源共133个文件,包含34个结构完整、语义清晰的HTML页面(如首页、商品详情、订…

2026/10/14 15:10:52 阅读更多 →
Webots 6 时代技术演进全解析:API 重构、OGRE 渲染迁移与物理引擎升级的版本档案

Webots 6 时代技术演进全解析:API 重构、OGRE 渲染迁移与物理引擎升级的版本档案

科研自动驾驶物理引擎 【免费下载链接】webots Webots Robot Simulator 项目地址: https://gitcode.com/gh_mirrors/web/webots 点击查看 免费下载 Webots 6 是机器人仿真器 Webots 从 5.x 走向现代架构的关键转折版本系列(2008 年末至 2012 年初&#…

2026/10/14 15:09:51 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →