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

数据结构 Trick 之:区间子区间计数

能够解决的问题

  • \(O(n \log n)\) 可过。
  • 维护数列,无修改每次查询一个区间的所有子区间
  • 离线

思路

看到一个区间的所有子区间这种查询,直接做显然是做不了的。

考虑离线,那么将询问区间进行右端点排序,然后就可以扫描线搞掉一维。

我们从左往右枚举 \(r\) 维护线段树 \(t\) 使得 \(t_l\) 维护的是区间 \([l, r]\)。在每次将 \(r\) 向右移的时候做一次修改。

但是此时还有一个问题,这样单词只能处理一个 \(r\),多个 \(l\),那么就要请出我们的历史信息线段树,这样就 OK 了。

例题与代码

CF997E Good Subsegments - 洛谷

标准的模板。

容易发现好区间就是 \((max - min) - (r - l) = 0\) 的区间,于是直接维护即可。至于极值的修改,用一个单调栈即可。

#include <bits/stdc++.h>
using namespace std;namespace gxk {void main() ;
}
int main() {ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);gxk::main();return 0;
}// ---#define int long long
#define umidd ((nodes[u].l + nodes[u].r) >> 1)
#define usz (nodes[u].r - nodes[u].l + 1)
namespace gxk {constexpr int maxn = 120010;int n, m, a[maxn], ans[maxn];struct qu {int l, r;} q[maxn];struct segnode {int l, r, minn, sum, hsum, tag, htag;} ;struct segtree {segnode nodes[maxn << 2];void pushup(int u) {nodes[u].minn = min(nodes[u << 1].minn, nodes[u << 1 | 1].minn);nodes[u].sum = 0;if (nodes[u << 1].minn == nodes[u].minn) nodes[u].sum += nodes[u << 1].sum;if (nodes[u << 1 | 1].minn == nodes[u].minn) nodes[u].sum += nodes[u << 1 | 1].sum;nodes[u].hsum = nodes[u << 1].hsum + nodes[u << 1 | 1].hsum;return ;}void build(int u, int l, int r) {nodes[u].l = l, nodes[u].r = r;if (usz == 1) {nodes[u].minn = l;nodes[u].sum = 1;return ;}build(u << 1, l, umidd);build(u << 1 | 1, umidd + 1, r);pushup(u);return ;}void modify(int u, int k) {nodes[u].minn += k;nodes[u].tag += k;return ;}void hmodify(int u, int k) {nodes[u].hsum += nodes[u].sum * k;nodes[u].htag += k;return ;}void pushdown(int u) {if (nodes[u].tag) {modify(u << 1, nodes[u].tag);modify(u << 1 | 1, nodes[u].tag);nodes[u].tag = 0;}if (nodes[u].htag) {if (nodes[u << 1].minn == nodes[u].minn) hmodify(u << 1, nodes[u].htag);if (nodes[u << 1 | 1].minn == nodes[u].minn) hmodify(u << 1 | 1, nodes[u].htag);nodes[u].htag = 0;}return ;}void update(int u, int l, int r, int k) {if (nodes[u].l > r || nodes[u].r < l) return ;if (nodes[u].l >= l && nodes[u].r <= r) {modify(u, k);return ;}pushdown(u);update(u << 1, l, r, k);update(u << 1 | 1, l, r, k);pushup(u);return ;}int query(int u, int l, int r) {if (nodes[u].l > r || nodes[u].r < l) return 0;if (nodes[u].l >= l && nodes[u].r <= r) return nodes[u].hsum;pushdown(u);return query(u << 1, l, r) + query(u << 1 | 1, l, r);}} t;struct edge {int l, idx;} ;vector <edge> G[maxn];stack <edge> sx, sn;void main() {cin >> n;for (int i = 1; i <= n; i++) {cin >> a[i];}t.build(1, 1, n);cin >> m;for (int i = 1; i <= m; i++) {cin >> q[i].l >> q[i].r;G[q[i].r].push_back({q[i].l, i});}sx.push({1145141919, 0});sn.push({-1145141919, 0});for (int i = 1, l, r, d; i <= n; i++) {t.modify(1, -1);while (sx.top().l < a[i]) {r = sx.top().idx;d = sx.top().l;sx.pop();l = sx.top().idx + 1;
//				cout << l << ' ' << r << '\n';t.update(1, l, r, a[i] - d);}sx.push({a[i], i});while (sn.top().l > a[i]) {r = sn.top().idx;d = sn.top().l;sn.pop();l = sn.top().idx + 1;
//				cout << l << ' ' << r << '\n';t.update(1, l, r, d - a[i]);}sn.push({a[i], i});t.hmodify(1, 1);for (edge now : G[i]) {ans[now.idx] = t.query(1, now.l, i);}}for (int i = 1; i <= m; i++) {cout << ans[i] << '\n';}return ;}
}
http://www.wxhsa.cn/company.asp?id=7956

相关文章:

  • mapstruct.Mapper|Mapping详解
  • 抽象代数-学习笔记
  • 如何在保证质量的前提下,快速完成一份 PPT?
  • Source Code Summarization in the Era of Large Language Models 论文笔记
  • 线性回归-入门案例
  • XXL-JOB(3)
  • ClickHouse 表引擎深度解析:ReplacingMergeTree、PARTITION、PRIMARY KEY、ORDER BY 详解 - 若
  • UOS统信服务器操作系统V20(1070)安装mysql8.4.5(建议安装glibc2.28版本)
  • web5(phps源码泄露)
  • web3(自带网络工具包查看数据)
  • web17(备份的sql文件泄露)
  • web11(通过Dns检查查询Flag)
  • ctfshow_web11
  • ctfshow_web13
  • ctfshow_web9
  • 锁屏界面无法通过任意键弹出开机密码
  • 应急响应-日志分析 - voasem
  • ctfshow web 10
  • SMA的射频连接器
  • 什么是Elasticsearch?它与其他搜索引擎相比有什么优势?
  • pdf.js-2.3.0国内下载地址
  • opencv学习记录2
  • get请求图片文件转为base64编码
  • BMS与威纶通人机界面通信问题
  • Blazor全栈是个陷阱
  • 大型语言模型安全实践:Copilot安全防护经验总结
  • 一些编程语言的发展史
  • mysql生成uuid,3种实用方法详解
  • vmware ubuntu共享文件夹
  • 【10章】n8n+AI工作流:从入门到企业级AI应用实战