倍增
为什么要倍增
倍增可以让我们在 n l o g n nlogn nlogn 的时间复杂度内解决问题,如区间最值(RMQ)问题,最近公共祖先(LCA)等,用处广泛。
RMQ ST表
区间最值问题,又称RMQ是指在任意l,r中找出最大值。
做法
我们首先考虑暴力,对于每一个询问,我们可以枚举l到r的元素,更新答案,时间复杂度为 O ( Q ( r − l + 1 ) ) O(Q(r-l+1)) O(Q(r−l+1)) Q为询问个数,l和r为询问区间。
我们考虑优化,我们可以维护一个二维数组 f [ i ] [ j ] f[i][j] f[i][j] 表示从 i i i 开始的 2 j 2^j 2j 个数中的最大值,显然 f [ i ] [ 0 ] = a [ i ] f[i][0]=a[i] f[i][0]=a[i],接下来我们考虑转移,对于每一个 f [ i ] [ j ] f[i][j] f[i][j],我们可以将其分为从 i i i 开始到 2 j − 1 2^{j-1} 2j−1 和从 i + 2 j − 1 i+2^{j-1} i+2j−1 开始到 2 j 2^j 2j 两部分,所以转移方程为(以最大值为例) f [ i ] [ j ] = m a x ( f [ i ] [ j − 1 ] , f [ i + ( 1 < < ( j − 1 ) ) ] ) [ j − 1 ] f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))])[j-1] f[i][j]=max(f[i][j−1],f[i+(1<<(j−1))])[j−1]。
对于每一个查询操作,我们可以先令 k = l o g 2 ( r − l + 1 ) k=log_2(r-l+1) k=log2(r−l+1)。则可将这段区间用 k k k 分为两段,则可以得出 m a x { a [ l ] , a [ l + 1 ] , ⋯ , a [ r ] } = m a x ( f [ l ] [ k ] , f [ r − ( 1 < < k ) + 1 ] [ k ] ) max \{ a[l],a[l+1], \cdots ,a[r] \} =max(f[l][k],f[r-(1<<k)+1][k]) max{a[l],a[l+1],⋯,a[r]}=max(f[l][k],f[r−(1<<k)+1][k])。
时间复杂度:预处理 O ( n l o g n ) O(nlogn) O(nlogn),单次询问 O ( 1 ) O(1) O(1)。
LCA
对于最近公共祖先,我们可以先假设两个点分别为 x , y x,y x,y,我们在维护一个二维数组 f [ i ] [ j ] f[i][j] f[i][j] 表示 i i i 节点的向上的第 2 j 2^j 2j 个节点是什么,显然 f [ i ] [ 0 ] f[i][0] f[i][0] 表示 i i i 的父节点,状态转移方程为 f [ i ] [ j ] = f [ f [ i ] [ j − 1 ] ] [ j − 1 ] f[i][j]=f[f[i][j-1]][j-1] f[i][j]=f[f[i][j−1]][j−1] 即 i i i 个向上 2 j − 1 2^{j-1} 2j−1 的节点的向上 2 j − 1 2^{j-1} 2j−1 个节点。
我们先假设 x x x 和 y y y 在同一深度,考虑从大到小枚举(假设当前枚举到 k k k),则当 f [ x ] [ k ] = f [ y ] [ k ] f[x][k]=f[y][k] f[x][k]=f[y][k] 时表示我们跳过了(即跳到了lca(x,y)或lca(x,y)的父节点),什么都不做,当 f [ x ] [ k ] ≠ f [ y ] [ k ] f[x][k] \neq f[y][k] f[x][k]=f[y][k] 时,令 x = f [ x ] [ k ] , y = f [ y ] [ k ] x=f[x][k],y=f[y][k] x=f[x][k],y=f[y][k] (即跳到 x x x 或 y y y 的第 2 k 2^k 2k 个节点上),当循环结束时,lca(x,y)必然是 x x x 或 y y y 的父节点,返回 f [ x ] [ 0 ] f[x][0] f[x][0] 或 f [ y ] [ 0 ] f[y][0] f[y][0] 即可。
考虑如果 x x x 与 y y y 不在同一深度时怎么做,我们假设 d e p [ x ] > d e p [ y ] dep[x]>dep[y] dep[x]>dep[y] (如果 d e p [ x ] < d e p [ y ] dep[x]<dep[y] dep[x]<dep[y] 则交换 x y x \, y xy),我们可以从大到小枚举(假设当前枚举到 k k k),若 d e p [ f [ x ] [ k ] ] ≤ d e p [ y ] dep[f[x][k]] \leq dep[y] dep[f[x][k]]≤dep[y],则令 x = f [ x ] [ k ] x=f[x][k] x=f[x][k],则当循环结束时 x x x 和 y y y 的深度就相同了。
时间复杂度:预处理 O ( n l o g n ) O(nlogn) O(nlogn),单次查询 O ( l o g n ) O(logn) O(logn)。