树(3.16

一道树状数组,一道图论,一道树链剖分

seqmod:如何将边权有序求和

先了解一下暴力30

模拟一下可以知道怎么处理

处理边权:将边权赋给它连接的两点(u,v)中的v

求和:(求lca,从链的两边往上跳,跳到lca)

有序:往上跳的时候,右子树(下几层)下面的点值最大,正序推

左子树(下几层)点值最小,逆序推

再了解一下大佬教的正解

大致思想:其实处理的很像是快读,ret=ret*10+p

但是很明显的是你一个个往上跳绝对绝对会超时,这时候我们就想到了倍增-->一次跳2的几次幂,那么这时候乘的肯定就不是2的0次方了而是2的i-1次方

我们考虑从下往上合并时的通解,(从上往下就同理,很好想了),跳一步合并的是a*10+b(下面的链是a,上面的是b)详见p201算法竞赛,那么跳2的i-1,通解就是a*10^2^(i-1)+b

 

rotinv : 树状数组求逆序对

去推如何从上一个状态到下一个状态(因为不可能每一个序列求一次逆序对),去找递推式

求逆序对:归并排序(O(N+M)logM)还是很大的

 

rise:

惊不惊喜

它其实是道图论题

首先肯定考虑相邻的,前面的大后面一定看不到,那么就把其建一条边,用dfs

但是怎么用树状数组来实现呢?

(好吧,其实也可以用树做啦)

正解:(其实就是贪心,每加入一个节点,去找个h——取max来更新,找以nd为节点中,询问去掉nd 这个节点中小于等于h
的数之后这个区间对应的答案.)

用线段树解决,每个节点维护:
• 最大值:vmax
• 这个区间对应的答案:c1
• 这个区间的右儿子(如果有的话)去掉小于等于左儿子最大值以后的剩下
的那些数对应的答案:c2
每个节点支持一种询问query(nd,h):询问去掉nd 这个节点中小于等于h
的数之后这个区间对应的答案.
假如我们可以实现上面这个操作的话,我们先将询问区间[L;R] 对应的那些
节点提取出来排好:nd1, nd2, nd3, ... nds.
query(nd1,0) + query( nd2, max(nd1)) + query(nd3,max(nd1,nd2)) + ... 就
是答案.
我们考虑怎样实现这个询问过程query(nd,h):
如果是叶子节点,只需要返回[h < a]  
如果h < nd 左儿子最大值,则返回query(nd 左儿子,h) + 右儿子c2
如果h >= nd,则返回query(nd 右儿子,h)
其实可以将query 看成我用h 去砍一刀,然后计算答案,上面的过程的正确
性还是比较容易理解的,如果我还有什么没有说清楚的可以看一下代码.
容易发现query 每次最多选两个儿子中的一个节点走下去,所以最多走
O(logn) 个节点,所以复杂度是O(logn) 的.
每个节点在算c2 时需要调用一次query,所以build 的时间复杂度是
O(nlogn) 的.
询问的时候,最多提取出来O(logn) 个区间,每个区间进行一次O(logn) 的
询问,所以单次询问是O(log2n) 的.
总的复杂度是O(nlogn + mlog2n) 的.

 

好吧,总结一下心得:线段树在处理区间时最重要的就是区间合并

 

posted @ 2019-03-16 16:06  白rap  阅读(82)  评论(0编辑  收藏  举报