首页 > 其他分享 >数据结构——猫树 学习笔记

数据结构——猫树 学习笔记

时间:2024-08-07 15:29:42浏览次数:14  
标签:log dep sum mid 笔记 int 猫树 mathcal 数据结构

数据结构——猫树 学习笔记

喵~

使用情景

没有修改,只有区间查询;且维护的信息可以快速合并且满足结合律。

我们直接抛出猫树的复杂度:预处理 \(\mathcal O(n\log n)\),查询 \(\mathcal O(1)\)

  • 如果询问的操作是可重复贡献问题(RMQ),那么她和 ST 表是理论复杂度相同的。

  • 如果询问的操作满足可减性(SUM),那么直接前缀和处理是更优的。

  • 如果查询次数 \(m\) 远小于元素个数 \(n\),那么线段树是更优的。

  • 否则,那么猫树是优于线段树等的。

预处理

下面直接记 \(m=\dfrac{l+r}2\),表示区间中点。

  1. 我们将区间 \([l,r]\) 分为两部分 \([l,m],[m+1,r]\)。

  2. 从 \(m,m+1\) 分别出发,向左、右遍历到 \(l,r\),同步维护要处理的信息。

  3. 递归左右区间。

复杂度分析:

  • 最多迭代 \(\mathcal O(\log n)\) 层;

  • 每一层的每一个元素会且仅会被访问一次,

  • 故,预处理总时间复杂度为 \(\mathcal O(n\log n)\)。

查询

对于询问区间 \([p,q]\),我们需要找到一个合适的线段树节点 \([l,r]\),

满足 \(l\le p\le q\le r\),那么我们就可以在这个节点上面直接合并前缀和后缀即可。

首先,我们显然可以从上到下把询问区间推到合适的层上,是 \(\mathcal O(\log n)\) 的。

然后我们发现可以从下往上找 LCA,树剖 \(\mathcal O(\log \log n)\) 的,ST 表 \(\mathcal O(1)\) 的。

但是这太复杂了,我们考虑堆式建树,此时,

  • 设根节点编号为 \(1\),子节点满足堆式,

  • 注意到一个节点编号的二进制表示,后 \(k\) 位就表示了向上 \(k\) 层的信息。

  • 因此,LCA 节点编号就是区间 \([l,r]\) 对应节点编号二进制表示的 LCP(最长公共前缀)。

  • 用公式表达就是 x >> __lg(x ^ y)

因此,我们就可以简单的在 \(\mathcal O(1)\) 查询了。

实现

题目:SP1043 GSS1 静态区间最大子段和

#define fill_over(x) ((1 << (__lg(x) + 1)) - 1)

constexpr int N = 1 << 16;

int n, m, a[N];

int pos[N], ans[20][N << 2], sum[20][N << 2];

void build(int k, int l, int r, int dep) {
    if (l == r) return void(pos[l] = k);
    int mid = (l + r) >> 1;
    // LEFT: [l, mid]
    sum[dep][mid] = a[mid];
    for (int i = mid - 1; i >= l; --i) sum[dep][i] = sum[dep][i + 1] + a[i];
    for (int i = mid - 1; i >= l; --i) sum[dep][i] = max(sum[dep][i], sum[dep][i + 1]);
    ans[dep][mid] = a[mid];
    for (int i = mid - 1; i >= l; --i) ans[dep][i] = max(ans[dep][i + 1], 0) + a[i];
    for (int i = mid - 1; i >= l; --i) ans[dep][i] = max(ans[dep][i], ans[dep][i + 1]);
    // RIGHT: [mid + 1, r]
    sum[dep][mid + 1] = a[mid + 1];
    for (int i = mid + 2; i <= r; ++i) sum[dep][i] = sum[dep][i - 1] + a[i];
    for (int i = mid + 2; i <= r; ++i) sum[dep][i] = max(sum[dep][i], sum[dep][i - 1]);
    ans[dep][mid + 1] = a[mid + 1];
    for (int i = mid + 2; i <= r; ++i) ans[dep][i] = max(ans[dep][i - 1], 0) + a[i];
    for (int i = mid + 2; i <= r; ++i) ans[dep][i] = max(ans[dep][i], ans[dep][i - 1]);
    // DOWN
    build(k << 1, l, mid, dep + 1);
    build(k << 1 | 1, mid + 1, r, dep + 1);
}

int query(int l, int r) {
    if (l == r) return a[l];
    int dep = __lg(pos[l]) - __lg(pos[l] ^ pos[r]);
    return max({ans[dep][l], ans[dep][r], sum[dep][l] + sum[dep][r]});
}

void init() {
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    m = fill_over(n) + 1, build(1, 1, m, 1);
}

标签:log,dep,sum,mid,笔记,int,猫树,mathcal,数据结构
From: https://www.cnblogs.com/RainPPR/p/18347111

相关文章

  • 数据结构——线段树优化 学习笔记
    数据结构——线段树优化学习笔记比较基础,因此讲的很快。我们主要关注单点修改、区间查询的线段树,这是应用最广泛的。线段树问题我们以LOJ的这道题为例,例题:LOJ#130.树状数组1:单点修改,区间查询。洛谷上面也有类似的题:P3374【模板】树状数组1。因为洛谷的题的数据范......
  • 数据结构——线段树提高 学习笔记
    数据结构——线段树提高学习笔记一些比较系统的东西,会单独放文章,这里只写一些理论的。线段树维护矩阵例题:P7453[THUSCH2017]大魔法师。当区间信息比较复杂,但是满足结合律的时候,可以使用矩阵维护。线段树每个节点维护一个矩阵,合并区间时使用矩阵乘法转移。但是,矩阵乘法的......
  • k8s学习笔记之CoreDNS
    一、CoreDNSconfigMap配置参数及说明主要讲解CoreDNSconfigMap及其他关键配置部署文件(需要替换其中一些变量):https://github.com/kubernetes/kubernetes/blob/master/cluster/addons/dns/coredns/coredns.yaml.base1.configMap配置apiVersion:v1kind:ConfigMapmetadat......
  • java笔记6
    10.多态多态的概念多态(Polymorphism)是面向对象编程的核心概念之一,它指的是同一个接口可以被多个不同的类实现,或者同一个操作作用于不同的对象时可以有不同的解释和行为。为何要用多态多态的使用使得代码更加灵活和可扩展,它允许编写的代码可以对不同类型的对象执行不同的操作。......
  • Living-Dream 系列笔记 第76期
    UVA1328简单题。我们有结论:对于一个周期串S的子串T,它的最小循环节即为T-nxt_{\left|T\right|}。(具体请查阅往期笔记)于是,我们枚举所有前缀,检验上式是否能被当前前缀的长度整除并且不止一个循环节即可。code#include<bits/stdc++.h>usingnamespacestd;constintN=......
  • 数据结构 - 并查集路径压缩
    ......
  • 【数据结构与算法】删除循环队列中第k个元素的算法 C++实现(循环队列+模运算)
    数组a[MaxSize]用作一个循环队列,front指向循环队列中队头元素的前一个位置,rear指向队尾元素的位置。设计删除队列中第k个元素的算法。思路首先,判断kkk是否在有效范围内......
  • 【数据结构与算法】在循环队列中第k个元素之后插入元素的算法 C++实现(循环队列+模运算
    数组a[MaxSize]用作一个循环队列,front指向循环队列中队头元素的前一个位置,rear指向队尾元素的位置。设计在队列中第k个元素之后插入item的算法。思路首先,检查输入的位置k是否在合理的范围内,即1到queueSize(Q)(包含两端)。如果k在这个范围外,那么返回ERROR。然后,计......
  • 笔记:从Aurora 8b/10b 到Aurora 64b/66b (三):自定义PHY层收发
    相较于8/10来说没那么复杂,需要考虑的情况只有八种;但是gearbox的控制需要额外的心思:每三十二周期所有操作都需要停止;这一点在收发都需要注意;RX:核心思想是利用header做检测,将夹杂在数据流中的控制包滤除掉;modulegt_phy_rx(inputwirei_rx_clk......
  • 《计算机网络 - 自顶向下方法》阅读笔记
    《计算机网络-自顶向下方法》阅读笔记应用层、运输层、网络层、数据链路层计算机网络和因特网:因特网:​ 是一个世界范围的计算机网络,互联了全世界的计算机设备计算机设备:手机,电脑,游戏机,电视等所有这些设备都称为主机(host)或端系统(endsystem)端系统通过通信......