用 C++ 解释 2D 线段/四叉树 [关闭]

2024-03-17

附:这可能不是重复的。我进行了搜索,并确保我没有得到我想要的东西。

我是一名 ACM 问题解决者,最近我学习了线性数组的线段树和具有延迟传播的线段树。但我遇到了一些需要 2D 线段树(在某处称为四叉树)的问题。但我找不到任何好的教程。我搜索了SO并找到了一个链接http://e-maxx.ru/algo/segment_tree http://e-maxx.ru/algo/segment_tree这是俄语教程。

我需要对 2D 线段树的源代码(最好是 C++)进行一些很好的解释。值得注意的是,我非常了解典型的线段树。


好吧,正如您所说,我希望您足够了解线段树(又名统计树)。我给出了多维线段树背后的一些直觉。


假设给你一个二维的N * N(对于相当大的 N,大到足以无法通过暴力处理)整数值网格,并且要求您执行操作 - 找到最小值/最大值或计算特定部分的所有项目的总和网格,更新任何网格索引值等。看起来,这个问题与典型的线段树问题没有什么不同,与数据容器的维度不同。这里可以选择构建一个 2D 线段树。

二维线段树的思想无非是四叉树 http://en.wikipedia.org/wiki/Quadtree- 树形数据结构,其中每个外部节点恰好有四个子节点。四叉树最常用于通过递归地将二维空间细分为四个象限或区域来划分二维空间。这些区域可以是正方形或矩形或者可以具有任意形状。 1974 年,Raphael Frinkel 和 J. L. Bentley 将这种数据结构命名为四叉树。类似的划分也称为Q-tree.

树的根包含完整的段[ (0, 0), (N - 1, N - 1) ]。对于每个细分市场[ (a1, b1), (a2, b2) ],我们将它们分成[ (a1, b1), ( (a1 + a2) / 2, (b1 + b2) / 2 ) ) ], [ ( (a1 + a2) / 2 + 1, b1 ), ( a2, (b1 + b2) / 2 ) ], [ ( a1, (b1 + b2) / 2 + 1 ), ( (a1 + a2) / 2, b2 ) ] and [ ( (a1 + a2) / 2 + 1, (b1 + b2) / 2 + 1 ), ( a2, b2 ) ] until a1 = b1 and a2 = b2。构建线段树的成本为O(nlogn)并准备好线段树来回答RMQ(范围最大/最小查询)可以在O(logn).

假设,给你一个网格N = 4。那么对应的树将是 -

如您所见,4 * 4 array [ (0, 0), (3, 3) ]分为 4 个子数组 –[ (0, 0), (1, 1) ], [ (2, 0), (3, 1) ], [ (2, 0), (1, 3) ] and [ (2, 2), (3, 3) ]。进一步,每四个块又被分割成四个更小的单元;例如段[ (2, 2), (3, 3) ][ (2, 2), (2, 2) ], [ (3, 2), (3, 2) ], [ (2, 3), (2, 3) ] and [ (3, 3), (3, 3) ]。这些段是最小的单元,因此不再进一步划分。

执行

与分割部分不同,编码部分与线段树非常相似。这里给出的代码是编程竞赛友好的(没有指针、内存分配/释放内容和 OOP 结构),我在竞赛中多次使用了这个片段。

#include <bits/stdc++.h>
 
using namespace std;
 
#define Max 501
#define INF (1 << 30)
int P[Max][Max]; // container for 2D grid
 
/* 2D Segment Tree node */
struct Point {
    int x, y, mx;
    Point() {}
    Point(int x, int y, int mx) : x(x), y(y), mx(mx) {}
 
    bool operator < (const Point& other) const {
        return mx < other.mx;
    }
};
 
struct Segtree2d {

    // I didn't calculate the exact size needed in terms of 2D container size.
    // If anyone, please edit the answer.
    // It's just a safe size to store nodes for MAX * MAX 2D grids which won't cause stack overflow :)
    Point T[500000]; // TODO: calculate the accurate space needed
    
    int n, m;
 
    // initialize and construct segment tree
    void init(int n, int m) {
        this -> n = n;
        this -> m = m;
        build(1, 1, 1, n, m);
    }
 
    // build a 2D segment tree from data [ (a1, b1), (a2, b2) ]
    // Time: O(n logn)
    Point build(int node, int a1, int b1, int a2, int b2) {
        // out of range
        if (a1 > a2 or b1 > b2)
            return def();
 
        // if it is only a single index, assign value to node
        if (a1 == a2 and b1 == b2)
            return T[node] = Point(a1, b1, P[a1][b1]);
 
        // split the tree into four segments
        T[node] = def();
        T[node] = maxNode(T[node], build(4 * node - 2, a1, b1, (a1 + a2) / 2, (b1 + b2) / 2 ) );
        T[node] = maxNode(T[node], build(4 * node - 1, (a1 + a2) / 2 + 1, b1, a2, (b1 + b2) / 2 ));
        T[node] = maxNode(T[node], build(4 * node + 0, a1, (b1 + b2) / 2 + 1, (a1 + a2) / 2, b2) );
        T[node] = maxNode(T[node], build(4 * node + 1, (a1 + a2) / 2 + 1, (b1 + b2) / 2 + 1, a2, b2) );
        return T[node];
    }
 
    // helper function for query(int, int, int, int);
    Point query(int node, int a1, int b1, int a2, int b2, int x1, int y1, int x2, int y2) {
        // if we out of range, return dummy
        if (x1 > a2 or y1 > b2 or x2 < a1 or y2 < b1 or a1 > a2 or b1 > b2)
            return def();
 
        // if it is within range, return the node
        if (x1 <= a1 and y1 <= b1 and a2 <= x2 and b2 <= y2)
            return T[node];
 
        // split into four segments
        Point mx = def();
        mx = maxNode(mx, query(4 * node - 2, a1, b1, (a1 + a2) / 2, (b1 + b2) / 2, x1, y1, x2, y2) );
        mx = maxNode(mx, query(4 * node - 1, (a1 + a2) / 2 + 1, b1, a2, (b1 + b2) / 2, x1, y1, x2, y2) );
        mx = maxNode(mx, query(4 * node + 0, a1, (b1 + b2) / 2 + 1, (a1 + a2) / 2, b2, x1, y1, x2, y2) );
        mx = maxNode(mx, query(4 * node + 1, (a1 + a2) / 2 + 1, (b1 + b2) / 2 + 1, a2, b2, x1, y1, x2, y2));
 
        // return the maximum value
        return mx;
    }
 
    // query from range [ (x1, y1), (x2, y2) ]
    // Time: O(logn)
    Point query(int x1, int y1, int x2, int y2) {
        return query(1, 1, 1, n, m, x1, y1, x2, y2);
    }
 
    // helper function for update(int, int, int);
    Point update(int node, int a1, int b1, int a2, int b2, int x, int y, int value) {
        if (a1 > a2 or b1 > b2)
            return def();
 
        if (x > a2 or y > b2 or x < a1 or y < b1)
            return T[node];
 
        if (x == a1 and y == b1 and x == a2 and y == b2)
            return T[node] = Point(x, y, value);
 
        Point mx = def();
        mx = maxNode(mx, update(4 * node - 2, a1, b1, (a1 + a2) / 2, (b1 + b2) / 2, x, y, value) );
        mx = maxNode(mx, update(4 * node - 1, (a1 + a2) / 2 + 1, b1, a2, (b1 + b2) / 2, x, y, value));
        mx = maxNode(mx, update(4 * node + 0, a1, (b1 + b2) / 2 + 1, (a1 + a2) / 2, b2, x, y, value));
        mx = maxNode(mx, update(4 * node + 1, (a1 + a2) / 2 + 1, (b1 + b2) / 2 + 1, a2, b2, x, y, value) );
        return T[node] = mx;
    }
 
    // update the value of (x, y) index to 'value'
    // Time: O(logn)
    Point update(int x, int y, int value) {
        return update(1, 1, 1, n, m, x, y, value);
    }
 
    // utility functions; these functions are virtual because they will be overridden in child class
    virtual Point maxNode(Point a, Point b) {
        return max(a, b);
    }
 
    // dummy node
    virtual Point def() {
        return Point(0, 0, -INF);
    }
};
 
/* 2D Segment Tree for range minimum query; a override of Segtree2d class */
struct Segtree2dMin : Segtree2d {
    // overload maxNode() function to return minimum value
    Point maxNode(Point a, Point b) {
        return min(a, b);
    }
 
    Point def() {
        return Point(0, 0, INF);
    }
};
 
// initialize class objects
Segtree2d Tmax;
Segtree2dMin Tmin;
 
 
// Driver program.
int main(void) {
    int n, m;
    // input
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            scanf("%d", &P[i][j]);
 
    // initialize
    Tmax.init(n, m);
    Tmin.init(n, m);
 
    // query
    int x1, y1, x2, y2;
    scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
 
    Tmax.query(x1, y1, x2, y2).mx;
    Tmin.query(x1, y1, x2, y2).mx;
 
    // update
    int x, y, v;
    scanf("%d %d %d", &x, &y, &v);
    Tmax.update(x, y, v);
    Tmin.update(x, y, v);
 
    return 0;
}

3D分割

给你一个 3D 网格并要求你执行类似 2D 线段树的操作并非不可能。在这种情况下,我们可以像构建 2D 网格一样构建 3D 线段树。

我们将网格分成8个更小的部分,并递归地进行细分,直到出现最小的单元。下图展示了这种分割思想。

对于一维线段树,我们将数组分为 2 (2^1) 个线段,并生成log2(n)特定操作的复杂性。同样对于 2D 线段树,我们将每一步中的 2D 网格分成 4 (2^2) 段,这确保了每个操作log2(n)成本。因此,以类似的方式,我们通过将网格细分为 8 (2^3) 段来扩展此 3D 树。

P.S.:3D线段树是我自己的想象;我不知道是否有类似的事情。可能对于 2D 和 3D 线段树有更好的方法,但我认为这些代码足以用于编程竞赛,因为我已经使用过很多次了。


Edit:

3D分割的想法只不过是Octree http://en.wikipedia.org/wiki/Octree- 树形数据结构,其中每个内部节点恰好有八个子节点。八叉树最常用于通过递归地将三维空间细分为八个八分圆来划分三维空间。八叉树是四叉树的三维模拟。

八叉树经常用于 3D 图形和 3D 游戏引擎。它还有很多其他应用,例如空间索引、最近邻搜索、三维高效碰撞检测以及so many http://en.wikipedia.org/wiki/Octree#Application_to_color_quantization.

希望能帮助到你!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用 C++ 解释 2D 线段/四叉树 [关闭] 的相关文章

  • 如何在 Visual Studio 2010 中增强 XAML 设计器?

    当我使用 XAML 设计器时 进入设计器和退出设计器是如此困难和缓慢 当我这样做时 Visual Studio 卡了一段时间 有什么方法可以增强 XAML 设计器和编辑器吗 Ant 保存 XAML 文件时非常慢 这通常意味着您可能有复杂的
  • 如何在 C++ 中的文件末尾添加数据?

    我已按照网上的说明进行操作 此代码应该将输入添加到文件 数据库 的末尾 但当我检查时 数据会覆盖现有数据 请帮忙 这是我的代码 int main string name string address string handphone cou
  • 用 C++ 进行服装建模 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在编写一些软件 最终会绘制一个人体框架 可以配置各种参数 并且计划是在假人身上放置某种衣服 我研究
  • 在 C# 中创建具有单独列的分隔文本

    我一直在尝试在 C 中创建一个制表符限制的文本文件 以便数据正确显示在单独的列中 Firstname Lastname Age John Smith 17 James Sawyer 31 我尝试过 t 字符 但我得到的只是 Firstnam
  • 拉伸数组

    我有一个形成曲线的样本向量 假设其中有 1000 个点 如果我想将其拉伸到填充 1500 个点 给出不错结果的最简单算法是什么 我正在寻找一些只有几行 C C 的东西 我总是想增加向量的大小 并且新向量可以是当前向量大小的 1 1 倍到 5
  • 互斥体实现可以互换(独立于线程实现)

    所有互斥体实现最终都会调用相同的基本系统 硬件调用吗 这意味着它们可以互换吗 具体来说 如果我使用 gnu parallel算法 使用openmp 并且我想让他们称之为线程安全的类我可以使用boost mutex用于锁定 或者我必须编写自己
  • 读取文件特定行号的有效方法。 (奖励:Python 手册印刷错误)

    我有一个 100 GB 的文本文件 它是来自数据库的 BCP 转储 当我尝试导入它时BULK INSERT 我在第 219506324 行上收到一个神秘错误 在解决此问题之前 我想看看这一行 但可惜的是我最喜欢的方法 import line
  • 用于检查项目文件中的项目变量和引用路径的 api

    我正在研究一个 net application VS2010 与 x 没有 解和变量号这些解决方案中的项目数量 我需要检查项目属性 特定于一定数量的项目 是否同质 并且检查 验证构建期间的参考路径 有没有一个API是这样的吗 如果没有 我该
  • 使用 C 语言使用 strftime() 获取缩写时区

    我看过this https stackoverflow com questions 34408909 how to get abbreviated timezone and this https stackoverflow com ques
  • 关于在 Windows 上使用 WiFi Direct Api?

    我目前正在开发一个应用程序 我需要在其中创建链接 阅读 无线网络连接 在桌面应用程序 在 Windows 10 上 和平板电脑 Android 但无关紧要 之间 工作流程 按钮 gt 如果需要提升权限 gt 创建类似托管网络的 WiFi 网
  • 使用 JNI 从 Java 代码中检索 String 值的内存泄漏

    我使用 GetStringUTFChars 从使用 JNI 的 java 代码中检索字符串的值 并使用 ReleaseStringUTFChars 释放该字符串 当代码在 JRE 1 4 上运行时 不会出现内存泄漏 但如果相同的代码在 JR
  • 未经许可更改内存值

    我有一个二维数组 当我第一次打印数组的数据时 日期打印正确 但其他时候 array last i 的数据从 i 0 到 last 1 显然是一个逻辑错误 但我不明白原因 因为我复制并粘贴了 for 语句 那么 C 更改数据吗 I use g
  • 如何将整数转换为 void 指针?

    在 C 中使用线程时 我面临警告 警告 从不同大小的整数转换为指针 代码如下 include
  • 将 log4net 与 Autofac 结合使用

    我正在尝试将 log4net 与 Autofac 一起使用 我粘贴了这段代码http autofac readthedocs org en latest examples log4net html http autofac readthed
  • std::async 与重载函数

    可能的重复 std bind 重载解析 https stackoverflow com questions 4159487 stdbind overload resolution 考虑以下 C 示例 class A public int f
  • HttpWebRequest 在第二次调用时超时

    为什么以下代码在第二次 及后续 运行时超时 代码挂在 using Stream objStream request GetResponse GetResponseStream 然后引发 WebException 表示请求已超时 我已经尝试过
  • C++ 密码屏蔽

    我正在编写一个代码来接收密码输入 下面是我的代码 程序运行良好 但问题是除了数字和字母字符之外的其他键也被读取 例如删除 插入等 我知道如何避免它吗 特q string pw char c while c 13 Loop until Ent
  • 如何在按钮单击时模拟按键 - Unity

    我对 Unity 中的脚本编写非常陌生 我正在尝试创建一个按钮 一旦单击它就需要模拟按下 F 键 要拾取一个项目 这是我当前的代码 在编写此代码之前我浏览了所有统一论坛 但找不到任何有效的东西 Code using System Colle
  • 编译时“strlen()”有效吗?

    有时需要将字符串的长度与常量进行比较 例如 if line length gt 2 Do something 但我试图避免在代码中使用 魔法 常量 通常我使用这样的代码 if line length gt strlen Do somethi
  • memset 未填充数组

    u32 iterations 5 u32 ecx u32 malloc sizeof u32 iterations memset ecx 0xBAADF00D sizeof u32 iterations printf 8X n ecx 0

随机推荐

  • Nodemailer 不会向 Outlook.office365 帐户发送电子邮件

    我正在尝试从 gmail 帐户发送电子邮件到接收者 即我的大学电子邮件 Outlook office365 它适用于gmail到gmail gmail到outlook live gmail到yahoo import as nodemaile
  • 从资产颤振中打开pdf文件

    我正在尝试使用 flutter fullpdfview 1 0 12 打开 PDF 文件 我的 PDF 文件位于 asset 文件夹下 但不知何故我收到错误 无法找到文件 我尝试了几个选项 但没有一个有效 并且都返回相同的错误 以下是我尝试
  • 为什么这个猪拉丁词转换代码不起作用

    Pig 拉丁语 单词转换 include
  • 如何使用 MVC RAZOR 将 DataTable 绑定到 DropDownList?

    我的模型返回数据表的集合 如下所示 如何使用 MVC RAZOR 将 DataTable 绑定到 DropDownList 对于每个数据表 我想为其创建一个表行和一个下拉列表 我尝试了下面的代码 foreach DataTable data
  • QHash存储大量数据

    我有 10 000 000 个 struct int int int int 类型的条目 当我使用它们存储时QHash http doc qt io qt 5 qhash html or QMap http doc qt io qt 5 q
  • 使用 Dojo 设置 元素的值/文本

    我正在开发一个秒表应用程序 试图学习 Dojo Toolkit 因此 首先 我需要将小时 分钟 秒和毫秒设置为 0 I tried dojo byId hours value 00 还尝试过 domAttr set hours 00 它不起
  • 使用 webpack 编译 less

    我想添加一个非常基本的 less 文件到我的project https github com pbrianmackey uiexperiment在 github 上 参见这次提交 https github com pbrianmackey
  • 如何使用expressJS提供ReactJS静态文件?

    问题 我已成功提供 React 应用程序的 index html 文件 但是index js取代
  • 从存在缺失值的现有列创建新列

    我正在尝试根据这两列创建一个新列 假设我想创建一个新列 z 当 y 不丢失时 它应该是 y 的值 当 y 确实丢失时 它应该是 x 的值 所以在这种情况下 我期望 z 是 1 8 10 8 x y 0 1 NaN 1 2 8 2 4 10
  • Sympy:化简平方根

    Sympy 似乎无法简化涉及变量平方的平方根的表达式 In 28 a x 2 In 29 b a 1 2 In 30 b Out 30 0 5 2 x In 31 b simplify Out 31 0 5 2 x 我无法将此与其他变体一起
  • 使用 PHP 7.2.4 的 Ubuntu 16.04 上缺少 PDO 驱动程序

    我想在Kubuntu 16 04上尝试最新版本的PHP 从那时起 我似乎无法将pdo与mysql一起使用 当我启动 php 时 出现以下警告 PHP Warning PHP Startup Unable to load dynamic li
  • 从 s3 读取文件时 joblib.load 出错

    当尝试从 s3 读取文件时joblib load 我收到错误ValueError embedded null byte当尝试读取文件时 这些文件是由 joblib 创建的 并且可以从本地副本 在上传到 s3 之前在本地制作 成功加载 因此错
  • 在 Backbone 中进行视图混合的正确方法

    我一直扩展基本主干视图 并且每个部分都有一个基本视图 以便我可以在多个级别上扩展 我的问题是 执行视图混合的最有效方法是什么 可以混合到任何视图中的可重用视图部分 例如 var BaseProfile Backbone View exten
  • Yahoo Pipes:根据文本文件中的单词过滤提要中的项目

    我有一个管道 可以过滤 RSS 提要并删除任何包含我选择的 停用词 的项目 目前 我已经在管道编辑器中为每个停用词手动创建了一个过滤器 但更合乎逻辑的方法是从文件中读取它们 我已经弄清楚如何从文本文件中读取停用词 但是如何将过滤器运算符应用
  • ReCaptcha 在 iPhone 上无法正常工作

    我有一个带有简单联系表格的网站 验证有点少 因为它不进入数据库 只是一封电子邮件 该表格的工作原理如下 有 5 个字段 其中 4 个为必填字段 提交将被禁用 直到 4 个字段有效 然后您才能提交 然后 所有内容都会在服务器上再次验证 包括验
  • Hibernate 完全支持 SQLite 吗?

    Jboss Hibernate 中没有提及对 SQLite 的支持its wiki https community jboss org wiki SupportedDatabases2 Stack Overflow 帖子中也提到了同样的内容
  • ggplot2刻度填充梯度与离散上限

    我正在寻找价值热图 我希望热图从表示低值的蓝色 示例代码中的 0 变为表示高值的绿色 示例代码中的 75 但是 数据包含大于 75 的值 我希望任何大于 75 的值都用红色填充 总而言之 我希望填充从 0 到 75 蓝色 到绿色 绿色 任何
  • 如何将es6语法添加到atom编辑器

    我曾经使用 sublime text 但现在想使用atom io 编辑器 我有这些代码行 error Missing semicolon import React Component from react export default cl
  • 根据 Java 编码标准进行异常处理

    我有一个关于异常处理情况下的java标准的查询 代码片段 public String methodXXX This method may throw IllegalArgumentexception and arrayoutofbounda
  • 用 C++ 解释 2D 线段/四叉树 [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 附 这可能不是重复的 我进行了搜索 并确保我没有得到我想要的东西 我是一名 ACM 问题解决者 最近我学习了线性数组的线段树和具有延迟传播的