动态开点

当正常堆式建树开不下时(\(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 进阶(?的更多相关文章

  1. Spring实战3:装配bean的进阶知识

    主要内容: Environments and profiles Conditional bean declaration 处理自动装配的歧义 bean的作用域 The Spring Expressio ...

  2. nodejs进阶(6)—连接MySQL数据库

    1. 建库连库 连接MySQL数据库需要安装支持 npm install mysql 我们需要提前安装按mysql sever端 建一个数据库mydb1 mysql> CREATE DATABA ...

  3. nodejs进阶(4)—读取图片到页面

    我们先实现从指定路径读取图片然后输出到页面的功能. 先准备一张图片imgs/dog.jpg. file.js里面继续添加readImg方法,在这里注意读写的时候都需要声明'binary'.(file. ...

  4. JavaScript进阶之路(一)初学者的开始

    一:写在前面的问题和话 一个javascript初学者的进阶之路! 背景:3年后端(ASP.NET)工作经验,javascript水平一般般,前端水平一般般.学习资料:犀牛书. 如有误导,或者错误的地 ...

  5. nodejs进阶(3)—路由处理

    1. url.parse(url)解析 该方法将一个URL字符串转换成对象并返回. url.parse(urlStr, [parseQueryString], [slashesDenoteHost]) ...

  6. nodejs进阶(5)—接收请求参数

    1. get请求参数接收 我们简单举一个需要接收参数的例子 如果有个查找功能,查找关键词需要从url里接收,http://localhost:8000/search?keyword=地球.通过前面的进 ...

  7. nodejs进阶(1)—输出hello world

    下面将带领大家一步步学习nodejs,知道怎么使用nodejs搭建服务器,响应get/post请求,连接数据库等. 搭建服务器页面输出hello world var  http  =  require ...

  8. [C#] 进阶 - LINQ 标准查询操作概述

    LINQ 标准查询操作概述 序 “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法.大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了IEnumerable<T> ...

  9. Java 进阶 hello world! - 中级程序员之路

    Java 进阶 hello world! - 中级程序员之路 Java是一种跨平台的语言,号称:"一次编写,到处运行",在世界编程语言排行榜中稳居第二名(TIOBE index). ...

  10. C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解

    前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学习Webapi的园友们速速动起来,跟着博主一起来学习吧.之前分享过一篇 C#进阶系列——WebApi接口传参不再困惑:传参详解  ...

随机推荐

  1. 【实战】Rust与前端协同开发:基于Tauri的跨平台AI阅读器实践

    一.背景与目标:为什么做一个"非典型"的RSS阅读器? 在信息爆炸的时代,RSS依然是高效获取结构化内容的重要方式,但市面上主流阅读器要么功能冗余(如集成社交属性),要么技术栈陈旧 ...

  2. python3里面实现将日志文件写入当前脚本运行的文本中

    在 Python3 中,可以使用 logging 模块来实现将日志写入本地文本文件中.下面是一个简单的示例代码: import logging # 配置 logging 模块 logging.basi ...

  3. 二十、基于Vant Weapp的生日管家

    目前市面上提供了一些免费开源的第三方小程序UI组件库,可以下载后放到项目文件夹中直接使用,比起开发者从头开始自定义组件更为方便.高效.本次考虑使用第三方UI组件来实现界面的视觉统一.本次以有赞第三方U ...

  4. 多多行动,Action And Think Not Thinking Thinking But Not Action

    行动和思考 为什么道理大家都懂,还是过不好我们自己的生活呢? 其实从小到大,我们了解和接触的大道理以及理论知识已经很多了,很多高深的哲学思想,有可能在我们小学的时候已经接触到了.种瓜得瓜,种豆得豆.一 ...

  5. 高效安全迁移:PG高可用集群实战方案深度解析

    PostgreSQL是一个开源的数据库管理系统,相比于其他开源数据库系统,PostgreSQL有更加丰富的数据类型和可扩展性,并因此被广泛采用.在实际工作中,若企业业务需求变动,则有可能面临PG高可用 ...

  6. 2-Tensorboard使用

    1. Tensorboard用途 ① Tensorboad 可以用来查看loss是否按照我们预想的变化,或者查看训练到某一步输出的图像是什么样. pip install tensorboard Req ...

  7. ARC158(A~D)

    Tasks - AtCoder Regular Contest 158 实际上是114514年前做的来着,非常好的数学(跟数论无关)/思维题集(\(A\)~\(D\)) A - +3 +5 +7 (a ...

  8. C++ map案例学习总结

    公司招聘5个员工,五名员工进入公司之后,需要指派员工在哪个部门工作 人员信息:姓名 年龄 电话 工资 等组成 通过Multimap进行信息的插入 保存 显示 分部门显示员工信息 显示全部员工信息 #i ...

  9. java---前端知识补充

    css的定位 相对定位: 相对定位是相对于元素原本的位置进行移动的. 使用方式: position:relative; 绝对定位: 绝对定位是相对于整个页面而言. position:absolute; ...

  10. js对象生成ts类型声明

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...