【异世界情绪】日文翻唱《鳥の詩/鸟之诗》
引个流,情绪的鸟之诗真的好听,听着这个学习效率巨高!

文章目录

  • 前言
  • 一、build函数
    • 演示①和②:
  • 二、add函数
    • 演示③:
  • 三、query函数
  • 四、最终的main函数
  • 总结

前言

说到线段树,就很难不想到那该死的build,add和query函数,完全不懂谁是用来干嘛的啦。而其他人写的博客对我来说不是那么容易理解,所以我在这里把这几天学到的关于线段树的知识记录下来。要是以后突然不懂了还能还看看,当然也方便像现在的我一样的正在学习算法的小白。

一、build函数

如其字面所示,build函数就是用来建树的,那么一般建树要干嘛呢?
这里就得先谈一下,tree一般有哪些元素了。当然,为了方便,一般会用一下struct。这里我们用一道题(HDU-1166)来说明。

/*那么我们读完题,这一颗树会有什么元素呢?*首先,一颗树应该有其左右子树的下标,如果左右下标相等,那么此时为叶子*即没有左右子树了*然后,这棵树应该还有用来记录区间总人数的元素sum*当然,我们应该还要写下一个记录营地人数的date[i],i指代某个营地*所以我们写下这样一个函数体**/#include <bits/stdc++.h>//直接万能库!( '▿ ' )using namespace std;const long long maxn=5e5+5;long long date[maxn];struct Tree{long long l,r;long long sum;}tree[maxn*4];/*为什么要开4倍空间呢?我给忘了,大家可以自己去查查*我之后也会去查查,再来更新这里的*/
//现在为build函数做完了准备工作,我们现在来写build!
void build(int l,int r,int i)/*l和r代表想从l到r建立树,i决定了谁来做根*或者说从i开始*写完build给大家演示一下①*/
{tree[i].l=l;tree[i].r=r;//更新i坐标的左右下标if(l==r){tree[i].sum=date[l];return;}//既然是叶子节点了,那么此时这//个节点的角色就是i营地了,应当记录i营地的人数//l和r不相等呢?该建立左右子树long long mid=(l+r)>>1;//这里是右移1位,在二进制的世界了相当于/2//即和long long mid=(l+r)/2等价build(l,mid,i<<1);//左子树build(mid+1,r,i<<1|1);//右子树//说明左右子树的下标规定为:其根的下标的2倍和2倍+1//即左子树li=i<<1,右子树ri=i<<1|1//现在跟新一下sum//上一节点的sum等于其左右子树的sum的和,也会演示一下②tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
}

演示①和②:

突然发现演示①、②可以用一个例子来同时说明!
演示用代码:

int main()
{int T;cin>>T;for(int x=1;x<=T;x++){int N;cin>>N;for(int y=1;y<=N;y++){cin>>date[y];}build(1,N,1);//修改处,只需修改i;for(int i=1;i<=128;i++){printf("%d: %d\n",i,tree[i].sum);}}return 0;
}

这里写开来是这样的:
不难发现sum是如何被一步步确定的,这个我实在不知道怎么掰开揉碎了给你讲了,你要这都看不懂,听我一句劝,360行,行行出状元。另择行业从事吧,你不适合编程。
划红线的地方的sum,但是此时他们都是叶子,没有左右儿子了,所以sum=date[i]。当然在图上我们发现,叶子的值的顺序正好是我们输入date[i]的顺序。但是他们的下标却不一样,是为什么呢?
为什么不一样呢?我们从对上面这副图进行推到,得到了这么一副图,于是我们能够明白tree[i]的下标是用来确定其在树中的位置的,与date[i]的下标无关。(为了接下来的说明方便、清楚,我们让tree[i]的i变为ti即tree[ti],同理date[i]变为date[di])
那么,ti和di有什么关系呢?ti和di的关系是由谁决定的呢?我们来看图中划红线的地方,不难发现此时的ti和我们输入的顺序相同,即此时ti=di。那么我们就返回观察build函数的代码发现:

if(l==r){tree[i].sum=date[l];return;}
long long mid=(l+r)>>1;
build(l,mid,i<<1);//左子树
build(mid+1,r,i<<1|1);//右子树

这几行代码起了关键作用,首先是第2行的mid,它使得当l!=r时左右子树的r和l分别得到了改变,从而达到了在不断的递归中使得l和r逐渐相等。并最终在第1行的if判断下使ti和di形成了联系。从而让相应位置的ti叶子存下了di的date的值。

如果改成build(1,N,2)
变为:

二、add函数

顾名思义add函数是用来给树里的东西加点什么的,当然作用还是取决于符号±嘿嘿~
那么在本题里,为了方便我们就通过符号来偷个懒,让add一个函数完成Add和Sub的命令吧。如下是代码:

void Add(int i,int j,int xb)//为什么题目说明明只有i,j2个参数传入我们
//还设置一个xb(下标)传入干什么?这个啊,我们之后再说( '▿ ' )
{//如果下标为xb的l和r都等于i的话,此时xb其实就等于i//此时我们发现,噢!原来xb是用来和i做比较的//if(tree[xb].l==i&&tree[xb].r==i){tree[xb]+=j;return ;}//但是为了好看一点,我们改写成:if(tree[xb].l==tree[xb].r){tree[xb].sum+=j;return ;}//我们接着来看else{//相等的说完了,该考虑考虑不等的情况了//不等说明此时不是叶子,所以我们先更新一下他的sumtree[xb].sum+=j;//这个时候可能就有同学要问了,啊你这个不应该不要嘛!//你都在上面的if更新了,你这里还+j干嘛!数据会不准的//可是,我们仔细想想,如果我们不更新的话,谁来更新呢?//要知道我们只建了一次树,如果想不写这一行的话,就代表着我们要不断//重新建树,而且这个操作还会很麻烦,所以我们要同时更新叶子的上级的sum//接着就是常规操作,利用递归来更新左右儿子,直到递归到叶子//要是i大于左儿子的r说明i在tree[zb]的r区间,即右儿子那边if(i>tree[xb<<1].r)Add(i,j,xb<<1|1);//这里也有演示③//不然就在左儿子那边else Add(i,j,xb<<1);}
}

演示③:

三、query函数

终于到了query(查询)函数了,淦,累死了( '▿ ’ )
这个函数式用来在i到j区间查询sum的,代码如下

int Query(int i,int j,int xb)//为什么是三个参数就不用我来说了吧( '▿ ' )
{//如果区间(tree[xb].l,tree[xb].r)等于区间(i,j)的话//直接就返回tree[xb].sum就可以了int mid=(tree[xb].l+tree[xb].r)>>1;//之后mid有用,自己看看( '▿ ' )if(tree[xb].l==i&&tree[xb].r==j)return tree[xb].sum;//要是不等就有三种情况,我们来看:else{//第一种,i>mid,那么ij在mid到tree[xb].r之间,即右子树嘛( '▿ ' )if(i>mid)return Query(i,j,xb<<1|1);//第二种,j<=mid,在左子树那边else if(j<=mid)return Query(i,j,xb<<1);//否则就是第三种,他脚踏两艘船,两边都有else return Query(i,mid,xb<<1)+Query(mid+1,j,xb<<1|1);}
}

于是,至此我们三个函数都写完了,该写main了!

四、最终的main函数

直接上代码!

int main()
{int T;cin>>T;for(int x=1;x<=T;x++){int N,i,j;cin>>N;memset(date,0,sizeof(date));///每次都要记得给date归零!for(int j=1;j<=N;j++)cin>>date[j];build(1,N,1);//建树,从1到N,下标1在最上面为顶cout<<"Case "<<x<<":"<<endl;string s;while(cin>>s){if(s=="End")break;cin>>i>>j;if(s=="Add")Add(i,j,1);//从1这个顶开始加if(s=="Sub")Add(i,-j,1);//同上if(s=="Query")cout<<Query(i,j,1)<<endl;}}return 0;
}

至此,我们终于写完了这道题,也基本讲明白了线段树是个啥。
开心!( '▿ ’ )

总结

说一下,我这个main是C++风格的,你要是直接拿走在本地是能过的,但oj上是会超时的,自己改成C风格的吧。写完了,开心~!( '▿ ’ )
然后,快去听情绪的《鳥の詩/鸟之诗》!

小小线段树 以HDU-1166 敌兵布阵为例相关推荐

  1. HDU 1166 敌兵布阵(线段树:点更新,区间求和)

    HDU 1166 敌兵布阵(线段树:点更新,区间求和) http://acm.hdu.edu.cn/showproblem.php?pid=1166 题意: 给你n个整数,然后给你多条命令,每条命令如 ...

  2. 树状数组板子题之一:hdu 1166 敌兵布阵

    树状数组板子题之一:hdu 1166 敌兵布阵 题目链接:hdu 1166 敌兵布阵 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手 ...

  3. hdu 1166 敌兵布阵(单点更新)

    hdu 1166 敌兵布阵(基本操作) 有三种操作:询问区间总和,增加某个兵营的兵的数目,减少某个兵营的兵的数目.实际上也只有两个. 在更新的时候,每到一个区间就把当前区间的sum增加对应的数目,到达 ...

  4. hdu 1166 敌兵布阵 (线段树)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  5. hdu 1166 敌兵布阵(线段树之 单点更新+区间求和)

    敌兵布阵                                                                             Time Limit: 2000/10 ...

  6. HDU 1166 敌兵布阵 【线段树-点修改--计算区间和】

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  7. HDU - 1166敌兵布阵+HDU-1754 I Hate It (线段树单点更新——累加/最大值)

    线段树单点更新,模板题 HDU1166 敌兵布阵 C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和T ...

  8. 线段树版子题【HDU - 1166 敌兵布阵】【HDU-1754 I Hate It】【HDU-1698 Just a Hook】【OpenJ_Bailian3439A Simple Pro】

    敌兵布阵 C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动 ...

  9. 【树状数组】HDU 1166 敌兵布阵

    敌兵布阵 日常题目胡乱总结 是个裸的树状数组qwq 区间查询+单点修改 字符判断相等那个地方我开始用的单引号 '  ' 直接不通过编译QAQ 第一遍交没有在一组数据结束后清空c数组 WA的让我很懵逼 ...

  10. hdu 1166 敌兵布阵 树状数组

    敌兵布阵                                                                           Time Limit: 2000/1000 ...

最新文章

  1. Java项目:家教管理系统(java+SSM+MyBatis+MySQL+Maven+Jsp)
  2. ORACLE用户权限管理笔记整理
  3. shell脚本——实现简单的功能
  4. 【温故知新】CSS学习笔记(三大特性)
  5. CRM_OPPORT_TEXT_DETER_STANDARD
  6. d3.js 获取当前像素坐标_Cesium开发入门篇 | 06坐标系及坐标变换
  7. php代码规范说明文档
  8. 广告行业一些常用物料的尺寸
  9. java代码实现解压文件_Java压缩/解压文件的实现代码
  10. leetcode1302. 层数最深叶子节点的和(深度优先搜索)
  11. 性能测试十四:Xshell链接linux虚拟机
  12. 279. 完全平方数(JavaScript)
  13. i2c电路电平转换电路
  14. 理解SaaS、PaaS、LaaS以及之间的区别
  15. 同花顺模拟炒股软件 v8.40.29 官方版
  16. 无心剑中译奥修《错在您》
  17. 学计算机毁一生,为什么说学医毁三代学法毁一生
  18. 【MySQL】DROP TABLE, TRUNCATE区别
  19. jsp + servlet 通过a 标签下载文件
  20. 中国各大银行网址及服务电话

热门文章

  1. 今日科技联播:程维确认滴滴上半年亏损40亿元,子弹短信未来六个月将烧10亿拉新...
  2. 2019-7-25 考试总结
  3. CATIA V6二次开发——Automation之属性和方法
  4. 小孩子如何学会说话?
  5. 在外包干了三年,我废了...
  6. windows录制android屏幕,如何使用Android Studio录制屏幕
  7. 仓鼠喜欢的23种设计模式(1)
  8. 刺客列传鸿蒙记,苒苒流年,春鸿秋燕,来往终何益。
  9. echarts柱状图两列单位不同
  10. 餐饮APP开发的几个基本功能