【给将来学神的算法详解--数据结构--线段树】(1)简介

来源:互联网 发布:ios 扑克牌效果源码 编辑:程序博客网 时间:2024/06/08 10:07

不了解这个数据结构,我们怎么学习呢?
————————————华丽的分割线————————————
一天,你坐在机房里面,惬意的喝着茶,正在打着一场NOIp级的,你由于你的主角光环神犇气场,已经AK了其他所有题目,这时候,有一个附加题蹦了出来。
题目1-1
题目1-2
看这个题目的口气不小,一定是一个很难的题目,于是,你打开翻译器,几阵键盘响后,你脱口而出:“我已经看透你的庐山真面目了!你就是一道数组维护题目!”,于是,你用一个普通数组维护这个输入数列就A掉了这道题。
话说这题真的是NOIp吗?
你又喝了几口茶,接着,又蹦出来一道题:
题目2-1
题目2-2
嗯。。。这题的确是增强了一点点,如果用刚才的方法,每次查询都是1~n的话,复杂度会达到nq,会T。
可这题毕竟还不是你的对手,你用前缀和来维护数组,记s[i]为1~i的和,初始化s[i]后,每个2操作就输出s[r]-s[l-1]就行了,于是,AK不在话下。
于是,又蹦出来了一道题(你:烦不烦啊!)
题目3-1
题目3-2
然后就尴尬了,如果直接用第一题的方法的话,修改的时间复杂度为1,但查询就会是On的,会T掉。
那如果用第2题的前缀和呢?
查询时间还是O1,没问题,但是修改就不一样了。修改一个数时,我们要把s数组中代表的累加和包括修改的数的东西全部更新,这是On的,会T掉。
嘲笑
难道就没有别的方法吗?
有的
如果我们要找到8个数1,2,3,4,5,6,7,8的和。我们有两个方法。
1(一个很常用的方法):
把1,2相加得3,再把3(是前两个数的和),3相加得6,再把6,4相加得1……最后你将算出36。
2(一个不常用的方法):
把1,2相加得3,再把3(是第三个数),4相加得7,再把5,6相加得11,再把7,8相加得15。
把3,7相加得10,把11,15相加得26,把26,10相加得36
如果你算出来不是这个值,那么恭喜你,你算错了
Q:这两种方法效率一样啊,而且第2个方法还要4-1的空间
A:接下来你就知道了
如果你把1改成0,算第1~第7的和,那怎么办?
1:
直接修改成0,然后把0,2相加得2,再把2……
2:
修改已知的第1个数,第1个+第2个的和,(第1个+第2个的和)+(第3个+第4个的和)的和。
然后把((第1个+第2个的和)+(第3个+第4个的和)的和)+(第5个+第6个的和)+第7个

题外话

Q:那也快不了多少啊

A:但是如果你把数据放大到65536,你会发现第1个方法要计算共65535次,修改1次,第二种方法只要计算16次,修改15次

Q:那第一种方法可以把第一次的答案减去最后一个数,修改一下第一个数产生的影响就行了啊

A:那要是再求3~5的值呢?你的代码就行不通了

这就是线段树

————————————华丽的分割线————————————

但在实际的应用当中,我刚才的算法还要改一改:修改时还要把总值修改一下,这样如果数据特别没良心每次查询都查总和就可以O1虐爆了

end

0 0