树上差分自己不算难
(
难的是天天爱跑步)
先说差分数组。
这个玩意,就是差分数组里的每一个值等于原数组这个位置的值减去原数组这个位置前面的值,但差分数组第一个值等于原数组第一个值。
估计童鞋们看不懂(◎﹏◎)
为此,我特意准备了栗子<( ̄︶ ̄)↗[GO!]
原数组a: 9 3 5 2 7
差分数组b:9 -6 2 -3 5
所以除了第一个特例,b[i]=a[i]-a[i-1] QwQ
但是,,,差分数组除了麻烦就是麻烦?那这个玩意就流行不起来了,肯定还是有利处,请往下看↓。
一道题,有n次操作,每一次要在[ l[n] , r[n] ]的区间内每一个数+x,x也可以是负数。
这也忒简单了吧!遍历l,r区间不就得了!跟这有什么关系?(╬▔皿▔)凸¬_¬
抱歉,就怕时间复杂度超了
当n增多之后,可能就要超时,后果自负 QwQ
所以?差分数组正式登场也!
差分数组求这道题分为三大部分:
- 预处理:原数组->差分
- n次操作
- 后期处理:求前缀和(差分->原数组)
预处理方法已经说了,重点探讨2. 3.
n次操作,就先一次吧(多次 一讲着麻烦,二听不懂,三我很懒QwQ)
以下l,r都指l[0],r[0],因为只有一次。
方法就是b[l]+=x,b[r+1]-=x.
或者去捡栗子(掉地了还能吃吗
比如我们要在[1,3]区间+1
那么9 -6 2 -3 5变成9 -5 2 -3 4
(⊙_⊙)?
Why?
因为-6=3-9,但是目标里3加了一,相当于:3+1-9,当然结果也加1,相反过来结果加1,9没动,3也就理想上加了一;简单说被减数加一,结果加一。
中间因为式两边都加所以差不变
b[r+1]个呢?因为减数加一,所以结果减一,反之亦然。
差分数组操作竟然这么简单!时间复杂度O(1)!!!( •̀ ω •́ )y
别着急,还有一步,前缀和。
反正就是新的b推出新的a。
b[i]=a[i]-a[i-1],那a[i]=b[i]+a[i-1]
栗子是不是又掉地了?pickitup!
如果i=1,那3=-6+9,而a[0]=b[0]=9,所以可以改成:a[1]=b[0]+b[1]
如果i=2,那a[2]=b[2]+a[1],但a[1]=b[0]+b[1],所以a[2]=b[0]+b[1]+b[2]
如果i=3,那a[3]=b[3]+a[2],但a[2]=b[0]+b[1]+b[2],所以a[3]=b[0]+b[1]+b[2]+b[3]
发现了其中的规(mì)律(mì)了吗?
所以! a i = ∑ k = 0 i b k a_i=\sum\limits_{k=0}^i b_k ai=k=0∑ibk
推出后即完成此题。
这个就是差分数组。
下面开始BB树上差分,
前面所有均是为以下做铺垫(是不是感觉还以为上面多重要,还细细的扣,结果落空╰(‵□′)╯?) 。。。请往下↓。
树上差分需要求LCA,即最近公共祖先。
我看的好多文章说LCA时都是一个链接过去,我只能进去看,看完了在回来看这个,我也懒得跑递归QwQ,正好也别让童鞋跑递归。。。2333
这里就详细介绍介绍
巨体思想 先把深度抬到一样高,然后一起往上 跳|爬 (借用了正则表达式符号d=====( ̄▽ ̄)b)
有两种方法
1.蜗牛型一步一步往上爬的暴力求解(一提到暴力,总是超时间的典型 )
2.青蛙型一步一步往上跳的倍增求解
蜗牛:没啥可说的,俩字:超时!
青蛙:大体思想(知道前面为什么用巨了吧 ):
移动速度要快!跳着走!
先预处理,
设数组 a n c i , j = i 往 上 走 2 j 个 anc_{i,j}=i往上走2^j个 anci,j=i往上走2j个, f a i = T h e F a t h e r O f I fa_i=The Father Of I fai=TheFatherOfI, d e e p i = i 的 深 度 deep_i=i的深度 deepi=i的深度
求出这些即可。
//基本转载:https://www.cnblogs.com/sllr15/p/5164996.html
int anc[1005][25];
int fa[1005];
vector <int > tree[1005];//tree[i]包含其子节点们
int deep[1005];
void dfs(int x)
{
anc[x][0<