定义
倍增法,顾名思义就是翻倍。它能够使线性的处理转化为对数级的处理,大大地优化时间复杂度。
这个方法在很多算法中均有应用,其中最常用的是 RMQ (Ranged Max/Min Query) 问题和求
LCA(Lowest Common Ancestor)。
引例
在你面前的桌子上,摆着无数个重量为任意整数的胡萝卜;
接着告诉你一个数字n,问你要怎么挑选,使得你选出的胡萝卜能够表示出 [1,n] 区间内的所有整数重量?
读完题后我们马上就能想到一种选法,那就是选n个重量为1的胡萝卜,这样就能通过加减表示出 [1,n] 内的所有重量了。
但问题是……这样挑选的胡萝卜是不是太多了点?
我们很快就能发现,只需要选择重量为 1,2,4,8 的胡萝卜,就能表示 [1,31] 内的所有重量。所以,只需要选择重量 20,21,22……2n 的胡萝卜,就能表示 [1,n] 内的所有重量。
也就是说, 对于给定的数字 ,根本不需要选那么多胡萝卜,只需要 个胡萝卜就够啦!
由此引例我们得出一个结论:只需要 的预处理,就能表示出 区间内的所有情况。
Vector扩容机制
std::vector 的 push_back() 操作是均摊线性的,其实现原理是每次 size 和 capability 相等并执行 push_back() 操作时,将申请一块约2倍大小的新空间,这样总 memcpy 操作的内存大小即是:
O ( N ) + O ( N / 2 ) + . . . + O ( 1 ) = O ( N ) O(N)+O(N/2)+...+O(1)=O(N) O(N)+O(N/2)+...+O(1)=O(N)
解法
-
ST表
模板 代码:
/* ST图 模板 此模板以(洛谷)P2880 [USACO07JAN] Balanced Lineup G 为标准 通用大部分ST图的题 */ #include <iostream> #include <algorithm> #include <cmath> using namespace std; #define int long long const int maxn=1e5+10; //此处可以修改 const int lg_maxn=__lg(maxn)+10; int a[maxn]; int f1[maxn][lg_maxn]; //max int f2[maxn][lg_maxn]; //min void init() //计算 { for (int i=1;i<=n;i++) f1[i][0]=f2[i][0]=a[i]; int k=log(n)/log(2); for (int j=1;j<=k;j++) { for (int i=1;i<=n-(1<<j)+1;i++) { f1[i][j]=max(f1[i][j-1],f1[i+(1<<(j-1))][j-1]); //此处可以修改 f2[i][j]=min(f2[i][j-1],f2[i+(1<<(j-1))][j-1]); //此处可以修改 } } } int query(int l,int r) //查找 { int p=log(r-l+1)/log(2); return max(f1[l][p],f1[r-(1<<p)+1][p])-min(f2[l][p],f2[r-(1<<p)+1][p]); //此处可以修改 } signed main() { int n,m; cin >> n >> m; for (int i=1;i<=n;i++) cin >> a[i]; init(); for (int i=1;i<=m;i++) { int l,r; cin >> l >> r; cout << query(l,r) << endl; } return 0; } /* 2023/12/13 10:29 修正1 2023/12/13 10:39 修正2 */ ```