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

标记永久化 - Denia

标记永久化

最开始我以为标记永久化只是 Lazy-tag 的替代品,但它真的很好用。

原理

在应用 Lazy-tag 技术的线段树中,查询时将所有包含在查询区间的小区间答案合并,一段区间的答案被直接保存在该区间节点内。为了达到这个目的,每次访问某个区间时,先利用 push_down 函数将该区间的正确答案计算出来(表现为将该节点到根节点路径上所有操作累加到该节点)。

标记永久化则没有 push_down 函数,但将 push_down 原本的功能转移到了查询函数,具体:

  • 更新时,更新到包含在内的最大区间(与传统线段树一样,只是没有 puhs_down)。
  • 查询时,将查询路径上所有点上的答案累加。

以区修单查区间最值为例(这是标记永久化最自然的一种应用):

int tg[]; // 只需要维护tg一个数组
void upd(int u,int l,int r,int ql,int qr,int v) {if (ql <= l && r <= qr) return tg[u] = max(tg[u],v),void();int mid = (l + r) >> 1;if (ql <= mid) upd(ls(u),l,mid,ql,qr,v);if (qr > mid) upd(rs(u),mid + 1,r,ql,qr,v);
}
int qry(int u,int l,int r,int p,int v) {if (l == r) return tg[u];int mid = (l + r) >> 1,ans = tg[u]; // 注意到累计每一层if (p <= mid) ans = min(ans,qry(ls(u),l,mid,p,v));else ans = min(ans,qry(rs(u),mid + 1,r,p,v));return ans;
}

对于区间修改区间查询,就不能只维护 tag,还需要维护节点子树内所有标记构成的区间和 sum
通过 push_up 维护 sum,显然可以得出:

\[sum_p=sum_{ls(p)}+sum_{rs(p)}+len\cdot tag_p \]

即:左右儿子贡献和自己直接的贡献。

int tg[],sum[];
void push_up(int u,int l,int r) {sum[u] = sum[ls(u)] + sum[rs(u)] + (r - l + 1) * tg[u];
}
void upd(int u,int l,int r,int ql,int qr,int v) {if (ql <= l && r <= qr) {tg[u] += v;sum[u] += v * (r - l + 1);return ;}int mid = (l + r) >> 1;if (ql <= mid) upd(ls(u),l,mid,ql,qr,v);if (qr > mid) upd(rs(u),mid + 1,r,ql,qr,v);push_up(u,l,r);
}
int qry(int u,int l,int r,int p,int v,int fa) { // fa: 来自祖先的标记if (ql <= l && r <= qr) return sum[u] + fa * (r - l +1 );int mid = (l + r) >> 1,ans = 0; // 注意到累计每一层 fa + tg[u]if (p <= mid) ans += qry(ls(u),l,mid,p,v,fa + tg[u]);else ans += ans,qry(rs(u),mid + 1,r,p,v,fa + tg[u]);return ans;
}

重点应用

扫描线

需先了解扫描线原理。

我们需要维护一个序列,这个序列所有至少被一个矩形覆盖的区间。

cnt 为区间被矩形完全覆盖的次数,\(sum\) 表示该区间答案,则有:

  • \(cnt>0\) 时,直接返回区间长度(离散值还原后)。
  • \(cnt=0\) 时,统计左右儿子答案,push_up 汇总到 \(sum\)

这是一个很显然的标记永久化,因为 cnt 不下传,只停留在一开始的区间。

struct SGT {
#define lson(x) (x << 1)
#define rson(x) (x << 1 | 1)struct node { int len,cnt; // 非0的长度,全区间被覆盖的次数 };node tr[4 * maxn + 5];inline void push_up(int u,int l,int r) {if (tr[u].cnt > 0) tr[u].len = pos[r] - pos[l];else tr[u].len = tr[lson(u)].len + tr[rson(u)].len;}void update(int u,int l,int r,int ql,int qr,int val) {if (ql <= l && r <= qr) {tr[u].cnt += val;push_up(u,l,r);return ;}int mid = (l + r) >> 1;if (qr <= mid) update(lson(u),l,mid,ql,qr,val);else if (ql >= mid) update(rson(u),mid,r,ql,qr,val);else update(lson(u),l,mid,ql,mid,val),update(rson(u),mid,r,mid,qr,val);push_up(u,l,r);}
};

例题

(咕咕咕……—— Denia-kawaii)

http://www.jsqmd.com/news/1399202/

相关文章:

  • boolinq:革命性C++11单文件LINQ库,让STL容器操作效率提升10倍
  • IntelliJ IDEA插件精选:16款提升Java开发效率的必备工具
  • 广西河池工艺好的汽车贴膜店实测,贴车衣、车身改色膜店测评榜,效果真好看 - 汽车新知百晓生
  • 为什么选择TorchVista?PyTorch模型调试与可视化工具对比评测
  • 如何用ESP32-CAM-Demo快速实现摄像头功能?3步完成OV7725模块配置
  • 课程论文截止前48小时:AI生成课程论文的急救方案
  • 从新手到专家:Tea Auto Bot高级功能与自动化策略
  • 编程竞赛必备资源:Programming Resources项目中的竞赛指南与技巧
  • 【数据结构】二叉树的遍历:层次遍历
  • 企业微信推送配置:mimotion刷步结果实时通知教程
  • Pyforms事件处理机制详解:打造响应式用户界面
  • arena1/arena与传统malloc对比:谁才是高性能应用的最佳选择?
  • 一招看清招聘信息发布时间:Boss Show Time 插件让陈旧职位无处遁形
  • Discord 附件上传上限翻倍至 20MB,移动应用检查文件大小逻辑与桌面端统一
  • 7.2.5.3 SIB1 的承载方式
  • 零成本搭建企业管理系统:用ERPNext开源ERP 30分钟跑通销售全流程
  • 加密音乐解锁终极指南:免费开源的 Unlock Music 音乐解密工具完整使用攻略
  • reserved-usernames项目进阶:自定义格式生成与自动化集成技巧
  • 旧款Mac免费升级最新macOS:OpenCore Legacy Patcher保姆级实战指南
  • PostCSS与Material Design Lite:Relay Fullstack样式解决方案
  • PDF补丁丁完整指南:5个实战场景,把乱糟糟的PDF收拾得服服帖帖
  • Ghidra 12.1 新特性深度解析:调试器为何不再“一崩全崩“
  • 12款Typora主题一次装齐,DrakeTyporaTheme完整上手体验记
  • 微信聊天记录如何永久保存?WeChatMsg导出工具保姆级实测指南
  • IP-Adapter图像提示适配器完全指南:如何用一张参考图掌控SD与SDXL创作
  • 《开拓者:正义之怒》角色构建进阶指南:拆解新手最常踩的6个坑,从零到毕业轻松通关
  • tfcausalimpact:基于TensorFlow Probability的终极因果推断工具详解
  • IntelliJ IDEA 2018.3 本地授权服务器部署与激活原理深度解析
  • tidb数据库3主机分布式集群docker-compose离线部署
  • 让浏览器秒变 Markdown 专业阅读器:Markdown Viewer 完整安装与使用指南