线段树这个算法,看起来非常高端,而且很有用处,所以还是讲一下下吧。

温馨提示:写线段树前请做好写码5分钟,调试一辈子的准备^-^

啊直接步入正题……

首先我们考虑一个题目:有一个序列,要做到单点修改单点查询,该怎么做呢?

同学们先不要着急关掉……我们细细分析,像这种题,明显大家都知道……直接暴力就过了嘛……,所以不做分析……

然后我们考虑第二个题目:有一个序列,要做到单点修改区间求和,该怎么做呢?

像传统的for(int i=1;i<=n;i++)ans+=a[i]当然是很香的,但如果遇到一些非常奇怪的题目(数 据 大 到 你 自 闭),这个就没什么用了……

啊这,简单的暴力不能用,就要用复杂的暴力——线段树,当然是简单亿点点的~因为单点修改可以O(1),不存在浪费时间的事情,所以我们用线段树小小的处理一下就好了。

接下来画一个图帮助斯烤:

在这个图上呢……一共有8个点,就是底下那些最小的线段,而我们把他合成了许多部分,每个部分的值就是f[wz*2]+f[wz*2+1](f是每个的值,wz是每个的编号)。

然后就可以把他一直向下,一直向下,直到发现这个区间是被我们要求的区间所包含的,然后这个区间内的数就全部加上,就这么一直向下找找找……,最后就可以算出一个区间的总和。

下面是演示代码~

void qh(long long wz)//wz是现在所处的小块编号

{

if(tree[wz].l>=a&&tree[wz].r<=b)//a和b是我们要求的区间的左右端点

{

zshu+=tree[wz].shu;//全部被包含,直接加上

return;

}

long long mid=(tree[wz].l+tree[wz].r)/2;//不能被包含?分裂一下试试吧

if(b>mid)//和谐小细节~

{

qh(wz*2+1);//如果有被包含,就去右边的小块看看

}

if(a<=mid)//和谐小细节*2~(至于为啥有和谐小细节,以及为什么要这样写,请同学们自己斯烤(这么简单还是可以的8))

{

qh(wz*2);//如果有被包含,也要去左边的小块看看

}

}

嘿嘿简单吧^-^,啊我忘记讲建树了QAQ。没事马上就讲。

建树嘛,直接递归就好了,每次把这个区间分成两份,一直分到l和r一样(就是说这是一个点的值,要输入了),然后获取两个点的值之后就可以向上递归~嗯嗯对,一直递归就建好了,相信大家都有这个写递归的能力,但要实在不会就看看下面的代码吧(温馨提示:线段树用来建树的数组要开到节点数的4倍大,至于为什么我也忘了……):

struct hehe

{

long long l,r,shu,f;

}tree[400005];//tree结构体~

long long mid;

void js(long long ll,long long rr,long long wz)//js,建树的意思。ll和rr分别是左右边界,wz就是他的编号

{

tree[wz].l=ll;//左边界是ll

tree[wz].r=rr;//右边界是rr

if(ll==rr)//左右边界一致,这是一个点

{

scanf("%lld",&tree[wz].shu);

return;

}

long long mid=(ll+rr)/2;//如果这不是一个点,肯定能分成两部分

js(ll,mid,wz*2);//左边

js(mid+1,rr,wz*2+1);//右边

tree[wz].shu=tree[wz*2].shu+tree[wz*2+1].shu;//加起来

}

看,是不是非常简单,接下来为了学的更深一点点,要把题目加难了(是的还要加难,但我相信你们一定可以学会的)

有一个序列,要做到区间增加区间求和,该怎么做呢?

啊这,这个是线段树里最难的一部分(起码我觉得最难),直接下放显然不太现实……,会浪费掉很多不必要的时间。正所谓科技发展在于懒人~,其实我们也可以在不影响结果的情况下偷个懒是吧QWQ。

就像加一样~我知道这两个序列的和,我就没必要去求所有单个序列是多少,加法和这个差不多,我们可以看看有那个序列是全都要加的,然后直接算出它加完之后的值。这样求这个值的时候肯定是不影响计算的(偷懒成功!)。但这时就会有一些同学吐槽:”啊你这个不严谨啊,如果下一次求和是求这个序列的一部分怎么办呢?”其实呢,我刚才也写了是吧……

其实我们也可以在不影响结果的情况下偷个懒是吧

我刚才说的是不影响,但这个操作明显影响了,在哪里影响了呢?就是只加了一个总序列,没有让他的一部分加上(偷懒失败QWQ)。但好像根本没有必要调整他的一部分啊,因为目前根本用不到,没说让做的事情我们还要去做不是浪费时间吗?但又不能不加,怎么办呢?我们可以设定一个懒标记,表示它之前被加了多少,这样呢,每次要求和的时候只要下放这个懒标记,并且加上该加的数,就能达到不说不做,最大程度优化时间,还保证正确hhhhh(偷懒成功)

至于代码的实现也是非常的简单:

void xf(long long wz)

{

tree[wz*2].shu+=(tree[wz*2].r-tree[wz*2].l+1)*tree[wz].f;//每个长度单位都加上tree[wz].f,总值就增加了(tree[wz*2].r-tree[wz*2].l+1)*tree[wz].f

tree[wz*2].f+=tree[wz].f;//之前每一个长度单位要加tree[wz*2].f,现在发现它还要加上tree[wz].f,就把他们两个加起来就好了嘛,很容易的。

tree[wz*2+1].shu+=(tree[wz*2+1].r-tree[wz*2+1].l+1)*tree[wz].f;

tree[wz*2+1].f+=tree[wz].f;//同理

tree[wz].f=0;//这里已经加过了,要清零的,就像转账一样,你给另一个人转了钱,你钱就没了。

}

上方是下放懒标记的代码,下方是区间修改代码:

void xg(long long wz)

{

if(tree[wz].l>=a&&tree[wz].r<=b)

{

tree[wz].shu+=(tree[wz].r-tree[wz].l+1)*c;//更改值

tree[wz].f+=c;//增加懒标记

return;

}//啊后面的都说过,不打了…

tree[wz].shu+=(min(tree[wz].r,b)-max(tree[wz].l,a)+1)*c;

long long mid=(tree[wz].l+tree[wz].r)/2;

if(b>mid)

{

xg(wz*2+1);

}

if(a<=mid)

{

xg(wz*2);

}

}

至于加了懒标记以后别的代码也是要动的。

比如在原来的求和代码里多了一个xf(wz);

至于加在哪里同学们自己斯烤吧(我太仁慈了)

啊我再放一道线段树模板题,大家可以秒掉来吊打我:模板题传送们

好了我觉得我讲完了,如果有什么不好或漏掉的地方大家可以及时评论,我会更改的。

程序员灯塔

转载请注明原文链接:C++算法 线段树

c语言线段树建树程序,C++算法 线段树相关推荐

  1. c语言线段树建树程序,c语言数据结构之线段树详解;例题:校门外的树(poj2808或者vijos1448)...

    线段树:它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个结点. 也就是说线段树的每一个结点对应一个区间,其中根节点对应区间[1,n] 对于线段树中的每一个非叶子节点[a,b],它的左儿子 ...

  2. java抢红包线段分割法_抢红包算法——线段分割法

    抢红包算法经常在面试的时候被问到,那么今天我就给大家分享一个比较常用容易理解的算法,线段分割法的实现. 算法思路: 线段分割法就是把红包总金额想象成一条线段,而每个人抢到的金额,则是这条主线段所拆分出 ...

  3. 基于Trie树的拼音切分算法

    基于Trie树的拼音切分算法 Trie树也叫做单词查找树,是一个非常有效的索引结构,trie是由retrieval演化而来的.具体介绍请参看–> [ 维基百科 ] Trie树结构的简单说明 Tr ...

  4. Algorithm:C++语言实现之SimHash和倒排索引算法相关(抽屉原理、倒排索、建立查找树、处理Hash冲突、Hash查找)

    Algorithm:C++语言实现之SimHash和倒排索引算法相关(抽屉原理.倒排索.建立查找树.处理Hash冲突.Hash查找) 目录 一.SimHash算法 1.SimHash算法五个步骤 2. ...

  5. 线段树 建树 单点修改 单点/区间查询

    线段树(sgement tree)是一种分治思想的二叉树结构,用于在区间上进行信息统计.与按照二进制位进行区间划分的树状数组相比,线段树是一种更加通用的结构: 线段树的每个节点都代表一个区间. 线段树 ...

  6. 数据结构源码笔记(C语言):B树的相关运算算法

    //B树的相关运算算法#include<stdio.h> #include<malloc.h>#define MAXM 10//定义B树最大的阶数 typedef int Ke ...

  7. c语言有啥简单的小程序,c语言-简单小程序-简单算法

    <c语言-简单小程序-简单算法>由会员分享,可在线阅读,更多相关<c语言-简单小程序-简单算法(19页珍藏版)>请在人人文库网上搜索. 1.以下小程序都在 TC2.0 中运行通 ...

  8. HDU 5669 Road(线段树建树)(分层图最短路)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5669 [分析]线段树建树+分层图最短路 #include <cstdio> #includ ...

  9. c语言伪代码怎么描述程序算法,伪代码是什么?如何写一个伪代码?

    伪代码是经常用于编程和基于算法的字段的术语:它是一种允许程序员表示算法实现的方法.简单地说,我们可以说它是算法的熟化表示.本篇文章就来带大家简单认识一下伪代码,介绍简单的C语言伪代码怎么写,希望对大家 ...

最新文章

  1. 不需要懂得编程,但却可以使用ggplot2画出论文级别的图?
  2. QToolButton设置背景无效的思考
  3. 系统调用回答为什么要用buffer写
  4. Rails 使用 Google Analytics 示例
  5. css 透明叠加_细品CSS(二)
  6. 嵌入式 uboot引导kernel,kernel引导fs
  7. 解决Node.js 运行的时候出现中文乱码问题
  8. Java-Integer和int有什么区别
  9. python使用-使用python进行数据清洗
  10. minicom在macos
  11. kafka常用的操作命令
  12. NERO9注册机使用
  13. Linux上Meson安装及使用
  14. vivo系统升级服务器无响应,vivo系统升级教程
  15. 企业网站的服务器配置,企业级服务器配置方案(网站服务器配置情况)
  16. ZCS证书的重新签发
  17. 新技术加速隐私暴露,我们该怎么办?(二)
  18. iphone同步android短信,如何从iPhone导入短信到Android手机?
  19. CTF MISC解题思路BUUCTF MISC1-8刷题
  20. 深入理解JVM之四:详解垃圾收集器

热门文章

  1. zabbix监控mysql日志告警_zabbix监控mysql以及报警(二)终
  2. 关于 SCJP 1.4 考试
  3. 51单片机入门 - 并行I/O口扩展实例(74LS244/74LS373/4071)
  4. Vuforia+Unity AR项目开发测试
  5. 东北大学和南邮的计算机,考研南邮跟东北大学通信与信息系统
  6. 360柱状全景图拼接
  7. 施一公 学生如何提高专业英文阅读能力
  8. WindowsXP/7/10 Python3.6.3开发环境配置图文教程
  9. DDR3 ECC 应用总结
  10. Power BI 关于日期显示格式的那些事儿