SGT 进阶(?
动态开点
当正常堆式建树开不下时(\(n\) 或 \(V\) 过大),通常使用动态开点。
例题
P2781 传教
算是很板了吧?
每次修改的时候,若当前访问节点未建立则新建节点并回溯至上一个节点记录左右儿子。实测写 & 引用或 struct 是很方便的。
要十分注意的是在 work 函数(单点修改 & 标记下放)里面一定要判断当前访问节点是否建立!
SGT namespace 代码:
namespace SGT {
#define mid (L + R) >> 1
#define son p, L, R
#define lson ls[p], L, (L + R) >> 1
#define rson rs[p], ((L + R) >> 1) + 1, R
int tot, ls[N], rs[N], tag[N], sum[N];
inline void psup(int p) {sum[p] = sum[ls[p]] + sum[rs[p]];}
inline void work(int &p, int L, int R, int k) {
if(!p) p = ++ tot;
tag[p] += k;
sum[p] += k * (R - L + 1);
}
inline void psd(int p, int L, int R) {
work(lson, tag[p]), work(rson, tag[p]);
tag[p] = 0;
}
inline void add(int l, int r, int k, int &p, int L = 1, int R = n) {
if(! p) p = ++ tot;
if(l <= L && R <= r) {
work(son, k);
return;
}
psd(son);
if(l <= mid) add(l, r, k, lson);
if(r > mid) add(l, r, k, rson);
psup(p);
}
inline int query(int l, int r, int &p, int L = 1, int R = n) {
int res = 0;
if(! p) return 0;
if(l <= L && R <= r) return sum[p];
psd(son);
if(l <= mid) res += query(l, r, lson);
if(r > mid) res += query(l, r, rson);
return res;
}
}
维护简单半群信息
用线段树解决问题,首先得考虑维护哪些信息。若不带修,任何满足结合律且封闭的信息(称为半群)都是可维护的。结合律一般都有,封闭性帮助我们设计信息。
—— Alex_Wei
通俗地讲,如果当前维护的信息是满足线段树的分治结构的,一般是可以维护的。
一般以最大子段和为典型代表。
例题
SP1716 GSS3 - Can you answer these queries III
区间最大子段和。
这个问题就是前文所述的典型的封闭性问题。
如果我们考虑答案纯粹从左子树或右子树转移而来的话,那么答案是沿树链严格递减的。因为我们忽略了最大子段和横跨左右区间的情况。
考虑维护最大前缀和、最大后缀和与最大子段和的标记,那么当前节点的最大子段和除了继承左右子树答案以外,还可以通过左区间的最大后缀和与右区间的最大前缀和转移而来。
那么又该如何去更新最大前缀和与最大后缀和的标记呢?首先还是一定可以继承。还有一种情况(以最大前缀和为例):若左区间的最大前缀和为左区间区间和,那么便可以继续拼接右区间的最大前缀和进行更新。最大后缀和亦然。
设 ans pre suf sum 为最大子段和、最大前缀和、最大后缀和与区间和,那么 psup 函数应为:
inline void psup(int p) {
t[p].sum = t[ls(p)].sum + t[rs(p)].sum;
t[p].pre = max(t[ls(p)].pre, t[ls(p)].sum + t[rs(p)].pre);
t[p].suf = max(t[rs(p)].suf, t[rs(p)].sum + t[ls(p)].suf);
t[p].ans = max({t[ls(p)].ans, t[rs(p)].ans, t[ls(p)].suf + t[rs(p)].pre});
return ;
}
值得一提的是像这样标记特别多的时候用 struct 会非常舒服。
第二个问题是我们只维护了一段线段树可以管辖到的区间的信息,若要查询应该怎么办。
考虑到线段树优秀的分治性质,我们分三段讨论。
- 询问区间包含当前访问的管辖区间
直接返回管辖区间的信息即可。
- 询问区间在当前访问的管辖区间中点左侧
即 \(r \le mid\)(\(r\) 为询问区间右端点,\(mid\) 为当前访问的管辖区间中点),递归解决当前访问的管辖区间中点左侧部分即可。
- 询问区间在当前访问的管辖区间中点右侧
即 \(l > mid\)(\(l\) 为询问区间左端点,\(mid\) 为当前访问的管辖区间中点),递归解决当前访问的管辖区间中点右侧部分即可。
- 询问区间横跨当前访问的管辖区间中点
先递归解决当前访问的管辖区间左右侧部分的问题,之后用类似 psup 的方法合并信息即可。
query 函数:
inline Node work(Node x, Node y) {
Node res;
res.sum = x.sum + y.sum;
res.pre = max(x.pre, x.sum + y.pre);
res.suf = max(y.suf, y.sum + x.suf);
res.ans = max({x.ans, y.ans, x.suf + y.pre});
return res;
}
inline Node query(int l, int r, int p = 1, int L = 1, int R = n) {
if(l <= L && R <= r) return t[p];
if(l > mid) return query(l, r, rson);
if(r <= mid) return query(l, r, lson);
Node lres = query(l, r, lson), rres = query(l, r, rson);
return work(lres, rres);
}
SGT 进阶(?的更多相关文章
- Spring实战3:装配bean的进阶知识
主要内容: Environments and profiles Conditional bean declaration 处理自动装配的歧义 bean的作用域 The Spring Expressio ...
- nodejs进阶(6)—连接MySQL数据库
1. 建库连库 连接MySQL数据库需要安装支持 npm install mysql 我们需要提前安装按mysql sever端 建一个数据库mydb1 mysql> CREATE DATABA ...
- nodejs进阶(4)—读取图片到页面
我们先实现从指定路径读取图片然后输出到页面的功能. 先准备一张图片imgs/dog.jpg. file.js里面继续添加readImg方法,在这里注意读写的时候都需要声明'binary'.(file. ...
- JavaScript进阶之路(一)初学者的开始
一:写在前面的问题和话 一个javascript初学者的进阶之路! 背景:3年后端(ASP.NET)工作经验,javascript水平一般般,前端水平一般般.学习资料:犀牛书. 如有误导,或者错误的地 ...
- nodejs进阶(3)—路由处理
1. url.parse(url)解析 该方法将一个URL字符串转换成对象并返回. url.parse(urlStr, [parseQueryString], [slashesDenoteHost]) ...
- nodejs进阶(5)—接收请求参数
1. get请求参数接收 我们简单举一个需要接收参数的例子 如果有个查找功能,查找关键词需要从url里接收,http://localhost:8000/search?keyword=地球.通过前面的进 ...
- nodejs进阶(1)—输出hello world
下面将带领大家一步步学习nodejs,知道怎么使用nodejs搭建服务器,响应get/post请求,连接数据库等. 搭建服务器页面输出hello world var http = require ...
- [C#] 进阶 - LINQ 标准查询操作概述
LINQ 标准查询操作概述 序 “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法.大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了IEnumerable<T> ...
- Java 进阶 hello world! - 中级程序员之路
Java 进阶 hello world! - 中级程序员之路 Java是一种跨平台的语言,号称:"一次编写,到处运行",在世界编程语言排行榜中稳居第二名(TIOBE index). ...
- C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解
前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学习Webapi的园友们速速动起来,跟着博主一起来学习吧.之前分享过一篇 C#进阶系列——WebApi接口传参不再困惑:传参详解 ...
随机推荐
- 基于 Streamlit 和 OpenAI 实现的小红书爆款文案生成器
项目介绍 在当今自媒体时代,高质量的文案是吸引流量的关键.特别是在小红书这样的平台上,一个吸引人的标题和富有情感的正文可以显著提高内容的曝光率. 本文将介绍一个基于OpenAI API和Streaml ...
- python实现小时划分
1.要实现图表如下图 2.后台的数据结构 说明:将每个小时按10分钟为一个时间间隔,分成6段,00.10.20.30.40.50然后将每个时间段组成如下数据:{'time': '22:30', 's ...
- odoo里面的动作
来源:Odoo中的五种action都是继承自ir.actions.actions模型实现的子类,共有五种,下面会一个一个给出具体例子 1.链接Action(ir.actions.act_url):ta ...
- 使用 Linux 命令 curl 和 telnet 测试接口连通性
摘要:接口可用性诊断利器curl和Telnet. 综述 Linux 中的命令 curl 是利用 URL 语法在命令行模式下工作的开源文件传输工具,它可以被用于测试API接口,查看响应头和发出HTT ...
- java list<对象>根据某个字段分组
前言 仅供学习参考,不保证性能问题 其中的实体类改成你自己的实体类 代码 /** * 根据某个字段进行分组,分组后遍历方法 * <p> * Map<String, List<M ...
- QRSuperResolutionNet:一种结构感知与识别增强的二维码图像超分辨率网络(附代码解析)
QRSuperResolutionNet:一种结构感知与识别增强的二维码图像超分辨率网络(附代码解析) 趁着 web开发课程 期末考试前夕,写一篇博客.{{{(>_<)}}} 将我最近所做 ...
- JS如何实现实时获取网络时间
首先我们列出常用的js获取网络时间的代码: getFullYear()获取年份 getMonth()获取月份[0-11] getDate()获取日 getHours()获取小时 getMinutes( ...
- 做思维导图?chatmoney轻轻松松拿下
本文由 ChatMoney团队出品 嘿,各位职场朋友们 是不是常常对着密密麻麻的笔记感到焦虑呢? 想整理却无从下手? 别怕,ChatmoneyAI知识库来拯救你的整理困难症啦! 咱们都知道,思维导图是 ...
- dotnetty 新的篇章- 开源
一.前言 因为微服务引擎依赖于dotnetty组件,很多协议都是针对于dotnetty 进行扩展,然后对于老版本https://github.com/azure/dotnetty 停止更新后,本人下载 ...
- 实现对C语言类学生管理系统文件存储的两种方法
学习javascript的时候曾经想做一个留言板的应用,但是却由于不知道如何存储失败了,由于做这个留言板的思路类似于C语言的学生管理系统,故此这次经历让我重新审视自己去学懂C语言的文件操作. 我重新用 ...