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

自己网站给别人网站做外链/关键词seo教程

自己网站给别人网站做外链,关键词seo教程,南宁市西乡塘区建设局网站,嘉兴网站建设运营目录 一、初识线段树 图例: ​编辑 数组存储: 指针存储: 理由: build函数建树 二、线段树的区间修改维护 区间修改维护: 区间修改的操作: 递归更新过程: 区间修改update&#xff1a…

目录

一、初识线段树

图例:

​编辑

数组存储:

指针存储:

理由:

build函数建树

二、线段树的区间修改维护

区间修改维护:

区间修改的操作:

递归更新过程:

区间修改update:

三、线段树的区间查询

区间查询:

区间查询的操作:

递归查询过程:

区间查询query:

例题:

完整代码:

数组实现:

指针实现:

总结


前言

今天我们来学习一下线段树

模板题目:P3372 【模板】线段树 1 - 洛谷


一、初识线段树

首先我们来了解一下什么是线段树

      线段树是一种数据结构,通常用来解决区间查询的问题。它主要用于对一个包含有 n 个元素的数组进行区间操作,如查询某个区间内的最大值、最小值、区间和等。

       线段树的基本思想是将整个数组按照一定规则进行分割,每个节点代表一个区间。每个节点保存区间内的信息,如最大值、最小值、区间和等。父节点的信息可以通过子节点的信息合并得到,这样就可以快速进行区间查询。

      线段树通常是一棵完全二叉树,叶子节点对应于数组中的元素,每个非叶子节点表示了其区间的信息。对于一个包含 n 个元素的数组,线段树的节点数一般是 2n-1 或 2^k-1,其中 k 是大于等于 n 的最小整数。线段树的构建包括建树和更新两个主要操作,查询时可以通过递归的方式进行。

       线段树在解决区间查询问题时效率很高,时间复杂度一般为 O(logn),其中 n 是数组元素个数。因此,线段树被广泛应用于需要频繁进行区间查询的场景,如动态区间最值查询、区间和查询等。

我这次是联系模板题目P3372 【模板】线段树 1 - 洛谷讲解的最简单的类型

图例:

      通过这幅图我们可以看出,线段树是根据不断的从子节点拿值,来更新父节点的值,直到得到整个区间的值,和分治的思想有点像,感觉

线段树的存储方式有两种常见的实现方法:数组存储和指针存储。

  1. 数组存储:

    • 在数组存储中,线段树被表示为一个静态的完全二叉树。数组的下标从 1 开始,对于节点 i,其左子节点为 2i,右子节点为 2i+1。
    • 如果线段树的叶子节点数量为 n,那么数组的大小一般取 4n,以确保足够的空间。
    • 线段树根节点一般存储在数组下标为 1 的位置。
    • 通过按照规则在数组中存储线段树的节点,可以方便地进行查询和更新操作。
  2. 指针存储:

    • 在指针存储中,线段树被表示为一个动态的树结构,每个节点通过指针指向其左右子节点。
    • 每个节点通常由一个包含左右子节点指针的结构体或类表示。
    • 指针存储方式在构建线段树时会动态生成节点,相对于数组存储来说更加灵活,但可能会消耗更多的内存空间。

     无论是数组存储还是指针存储,线段树的基本操作都是相似的,包括建树、查询和更新。选择适合具体应用场景的存储方式可以更好地利用线段树的优势,提高算法效率。

      首先是数组存储,我们最先要知道的是数组的大小需要开多大,在线段树的数组存储中,通常会将数组的大小设置为 4n,其中 n 表示线段树的叶子节点数量。

理由:

  1. 完全二叉树性质:线段树一般是一棵完全二叉树,具有规律性的结构。在数组存储方式下,为了方便表示完全二叉树,需要保证数组的大小是某一层节点数量的上限。对于一棵深度为 k 的完全二叉树,叶子节点数量最多为 2^k,因此数组大小一般设置为 4 * 2^k,以确保足够的空间。

  2. 节点的父子关系:在数组存储方式中,节点 i 的左子节点一般存储在位置 2i,右子节点存储在位置 2i+1。设置数组大小为 4n 可以保证对于任意节点 i,其子节点在数组中的位置都是有效的,不会越界。

  3. 方便计算左右子树位置:在线段树的查询和更新操作中,经常需要根据节点的索引快速定位其左右子树节点。通过设置数组大小为 4n,可以方便地根据节点索引计算出其左右子节点的位置,简化操作。

然后开一个build函数建树,具体操作如下:

  1. 定义数组:首先,需要定义一个大小为 4n 的数组,其中 n 是线段树的叶子节点数量。这个数组将用于存储线段树的节点信息。

  2. 构建线段树:一般将线段树按照完全二叉树的形式存储在数组中。假设根节点在数组中的索引是 1,那么对于节点 i,其左子节点为 2i,右子节点为 2i + 1。

  3. 存储节点信息:每个节点需要保存代表的区间范围和相应的信息,比如区间的最大值、最小值、和等等。在数组中,可以按照某种顺序依次存储这些信息,以便后续的查询和更新操作。

  4. 建立线段树:通过递归或迭代的方式构建线段树。一般会从叶子节点开始向上构建,通过合并子节点的信息得到父节点的信息,直至构建完整的线段树。

  5. 查询和更新:通过线段树的结构和数组存储,可以实现高效的区间查询和更新操作。比如,对于查询一个区间的最大值,可以通过递归向下查询到包含目标区间的节点,并根据存储的信息计算出结果。

  6. 记得注意边界情况:在实现线段树时,需要考虑树的边界情况,比如树的根节点索引是 1,叶子节点索引从 n+1 开始等,以确保正确地访问和操作节点。

build函数建树

void build(LL l, LL r, LL fa) {if (l == r) // //如果左右区间相同,那么必然是叶子节,只有叶子节点是被真实赋值的{t[fa] = a[l];return;}LL mid = (l + r) >> 1;build( l, mid, fa << 1);build(mid + 1, r, fa << 1 | 1);
//使用二分来优化psuh_up(fa);//此处由于我们是要通过子节点来维护父节点,所以push_up的位置应当是在回溯时将子节点的值取和交给父节点
}

二、线段树的区间修改维护

      线段树是一种用于解决区间查询和修改问题的数据结构。在线段树中,区间修改维护指的是在给定一个区间,并修改该区间内所有元素的操作。

  1. 区间修改维护

    • 当需要修改线段树中某个特定区间的值时,可以通过递归的方式向下更新区间。
    • 如果要修改的区间与当前节点表示的区间没有交集,则无需修改该节点。
    • 如果要修改的区间完全包含当前节点的区间,则直接更新当前节点的信息,并将修改操作下传给子节点。
    • 如果要修改的区间与当前节点的区间部分相交,则需要先将当前节点的信息更新,然后将修改操作同时下传给左右子节点。
  2. 区间修改的操作

    • 区间修改的操作通常包括加法、减法、赋值等。
    • 当需要对区间内的每个元素进行相同的修改时,可以利用线段树的特性进行高效操作。
    • 在修改区间时,需要根据当前节点的区间范围、待修改区间和修改方式来确定如何操作当前节点和其子节点。
  3. 递归更新过程

    • 从线段树的根节点开始递归向下更新,直到找到包含待修改区间的叶子节点。
    • 在递归过程中根据节点的区间范围和待修改区间的关系,决定如何更新节点的信息并向下传递修改操作。

       此外,对于区间操作,我们考虑引入一个名叫“ lazy tag ”(懒标记)的东西——之所以称其“lazy”,是因为原本区间修改需要通过先改变叶子节点的值,然后不断地向上递归修改祖先节点直至到达根节点,时间复杂度最高可以到达 O(nlogn) 的级别。但当我们引入了懒标记之后,区间更新的期望复杂度就降到了 O(logn) 的级别且甚至会更低。

因此,我们再弄一个tag数组,大小也是4*N

区间修改update:

void psuh_up(LL fa) {t[fa] = t[fa << 1] + t[fa << 1 | 1];//向上不断维护父节点
}
void push_down(LL l,LL r,LL fa) {LL mid = (l + r) >> 1;t[fa << 1] += tag[fa] * (mid - l + 1);tag[fa << 1] += tag[fa];t[fa << 1|1] += tag[fa] * (r-mid);tag[fa << 1|1] += tag[fa];tag[fa] = 0;// //每次将懒惰标识下放到两个儿子节点,自身置为0,以此不断向下传递 
}
void update(LL ql, LL qr, LL l, LL r, LL k, LL fa) {if (ql <= l && qr >= r) //如果区间被包含,直接返回该节点的懒惰标识{t[fa] +=k * (r - l + 1);tag[fa] += k;return;}LL mid = (l + r) >> 1;push_down(l, r, fa);//下放懒惰标识if (ql <= mid)update(ql, qr, l, mid,k, fa << 1);//朝左边下放if (qr > mid)update(ql, qr, mid + 1, r,k, fa << 1 | 1);//右边psuh_up(fa);//再将修改后的值向上返回,维护父节点
}

三、线段树的区间查询

  1. 区间查询

    • 当需要查询线段树中某个特定区间的信息时,可以通过递归的方式向下查询区间。
    • 如果要查询的区间与当前节点表示的区间没有交集,则无需查询该节点,直接返回默认值(如0或无穷大)。
    • 如果要查询的区间完全包含当前节点的区间,则直接返回该节点存储的信息。
    • 如果要查询的区间与当前节点的区间部分相交,则需要同时查询左右子节点,并根据查询结果合并得到最终结果。
  2. 区间查询的操作

    • 区间查询的操作通常包括求和、求最大值、求最小值等。
    • 在查询区间时,需要根据当前节点的区间范围、待查询区间和查询方式来确定如何操作当前节点和其子节点。
  3. 递归查询过程

    • 从线段树的根节点开始递归向下查询,直到找到包含待查询区间的叶子节点。
    • 在递归过程中根据节点的区间范围和待查询区间的关系,决定如何查询节点的信息并向下传递查询操作。
    • 最终将所有查询结果合并得到最终的区间查询结果。

      通过以上方法,可以实现对线段树中特定区间的查询操作。线段树区间查询是线段树的一个重要功能,能够快速有效地获取区间内的信息,提高了区间查询的效率。

区间查询query:

LL query(LL ql, LL qr, LL l, LL r, LL fa) {LL ret = 0;if (ql <= l && qr >= r) 如果区间被包含,直接返回该节点的懒惰标识{return t[fa];}LL mid = (l + r) >> 1;push_down(l, r, fa);//没有被包含,下放任务if (ql <= mid)ret += query(ql, qr, l, mid, fa << 1);if (qr > mid)ret += query(ql, qr, mid + 1, r, fa << 1|1);//在查询范围的左区间和右区间的值相加并返回return ret;
}
例题:

模板题目:P3372 【模板】线段树 1 - 洛谷

完整代码:
数组实现:
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
typedef long long LL;
LL n, m, t[N * 4], tag[N * 4], a[N];
void psuh_up(LL fa) {t[fa] = t[fa << 1] + t[fa << 1 | 1];//向上不断维护父节点
}
void push_down(LL l,LL r,LL fa) {LL mid = (l + r) >> 1;t[fa << 1] += tag[fa] * (mid - l + 1);tag[fa << 1] += tag[fa];t[fa << 1|1] += tag[fa] * (r-mid);tag[fa << 1|1] += tag[fa];tag[fa] = 0;// //每次将懒惰标识下放到两个儿子节点,自身置为0,以此不断向下传递 
}
LL query(LL ql, LL qr, LL l, LL r, LL fa) {LL ret = 0;if (ql <= l && qr >= r) 如果区间被包含,直接返回该节点的懒惰标识{return t[fa];}LL mid = (l + r) >> 1;push_down(l, r, fa);//没有被包含,下放任务if (ql <= mid)ret += query(ql, qr, l, mid, fa << 1);if (qr > mid)ret += query(ql, qr, mid + 1, r, fa << 1|1);//在查询范围的左区间和右区间的值相加并返回return ret;
}
void update(LL ql, LL qr, LL l, LL r, LL k, LL fa) {if (ql <= l && qr >= r) //如果区间被包含,更新懒惰标识并返回{t[fa] +=k * (r - l + 1);tag[fa] += k;return;}LL mid = (l + r) >> 1;push_down(l, r, fa);//下放懒惰标识if (ql <= mid)update(ql, qr, l, mid,k, fa << 1);//朝左边下放if (qr > mid)update(ql, qr, mid + 1, r,k, fa << 1 | 1);//右边psuh_up(fa);//再将修改后的值向上返回,维护父节点
}
void build(LL l, LL r, LL fa) {if (l == r) // //如果左右区间相同,那么必然是叶子节,只有叶子节点是被真实赋值的{t[fa] = a[l];return;}LL mid = (l + r) >> 1;build(l, mid, fa << 1);build(mid + 1, r, fa << 1 | 1);//使用二分来优化psuh_up(fa);//此处由于我们是要通过子节点来维护父节点,所以push_up的位置应当是在回溯时将子节点的值取和交给父节点
}
int main() {cin >> n >> m;for (int i = 1; i <= n; i++)cin >> a[i];build(1, n, 1);while (m--) {int op; cin >> op;if (op == 1) {LL x, y, k; cin >> x >> y >> k;update(x, y, 1, n, k, 1);}else if(op==2){LL x, y;cin >> x >> y;cout << query(x, y, 1, n, 1) << endl;}}return 0;
}
指针实现:
#include <iostream>
#include <vector>using namespace std;struct Node {int start, end;int sum;Node *left, *right;Node(int start, int end) : start(start), end(end), sum(0), left(nullptr), right(nullptr) {}
};Node* buildSegmentTree(vector<int>& nums, int start, int end) {if (start > end) {return nullptr;}Node* root = new Node(start, end);if (start == end) {root->sum = nums[start];} else {int mid = start + (end - start) / 2;root->left = buildSegmentTree(nums, start, mid);root->right = buildSegmentTree(nums, mid + 1, end);root->sum = root->left->sum + root->right->sum;}return root;
}int query(Node* root, int qs, int qe) {if (root == nullptr || qs > root->end || qe < root->start) {return 0;} else if (qs <= root->start && qe >= root->end) {return root->sum;} else {return query(root->left, qs, qe) + query(root->right, qs, qe);}
}int main() {vector<int> nums = {1, 3, 5, 7, 9, 11};Node* root = buildSegmentTree(nums, 0, nums.size() - 1);cout << "Sum of elements in range [2, 4]: " << query(root, 2, 4) << endl;return 0;
}


总结

本文关于线段树的讲解就到这里,有什么疑问或者有什么错误的地方欢迎一起交流学习

http://www.whsansanxincailiao.cn/news/30247212.html

相关文章:

  • 南阳网站制作/宝塔没有域名直接做网站怎么弄
  • 嘉兴seo网站建设费用/需要推广的app在哪里找
  • 手车做网课网站多少/百度集团股份有限公司
  • 阿里云虚拟主机可以做几个网站/网络营销推广方案ppt
  • 藏族网站建设/google关键词搜索工具
  • 路桥建设局网站/网站seo优化徐州百度网络
  • 天成信息网站建设自助建站平台/怎样搭建自己的网站
  • 网站关键词引流/酒店线上推广方案有哪些
  • 西宁市网站建设公司/实时新闻
  • 做app网站有哪些功能/持续优化完善防控措施
  • 有经验的宁波网站建设/jmr119色带
  • 文化建设 设计公司网站/nba最新交易新闻
  • wordpress仿百度首页/天津百度关键词seo
  • 免费建设商城网站/新冠疫苗接种最新消息
  • 新网网站空间独立控制面板/江门搜狗网站推广优化
  • 基于jsp的网上购物系统/seo引擎优化方案
  • 电子商务网站建设及推广方案论文/性价比高seo的排名优化
  • 厦门网站设计大概多少钱/百度快照网站
  • 淘宝网站代理怎么做/常用的搜索引擎有哪些
  • 网站配色模板/个人网页制作
  • 百度对网站建设公司/新网站秒收录技术
  • 高中信息技术网站设计规划/廊坊关键词优化排名
  • 网站开发技术有哪些/连云港seo优化公司
  • 做国外网站什么定位/万网
  • 黄埔定制型网站建设/seo一个关键词多少钱
  • 怎么做区块链媒体网站/推广方法
  • 内蒙古企业网站建设/深圳高端seo外包公司
  • 义乌网站建设工作室/福州短视频seo网站
  • 如何注册企业邮箱免费/网站seo内容优化
  • 济南网站假设推广/seo交流qq群