Improved RMQ
2015-10-01 18:03
295 查看
因为有点无聊,所以打了一下这个算法,发现还可以。卡常必备。
接着对于一个询问,假设为l,r.设Blocki表示位置i所属的块。那么我们可以把一个询问分为三段。第一段为Blockl中l到结尾。第二段为Blockl+1→Blockr−1.第三段为Blockr中起点到r.
那么因为对于已经处理出ST表的地方可以O(1)完成询问。所以我们的询问也是O(1)的。
那么总的时间复杂度就是O(N+Nlog(logN)+Q)了。
原问题
给定N个数Ai.有Q个询问,每个询问询问一段区间的最小(大)值。经典做法
RMQ问题的经典做法是ST表。即先预处理出Fi,j,表示以i为起点,长度为2j的一段的最小值是多少。然后在询问的时候直接把区间拆成两段可能重复的区间来取个min。这样预处理的时间复杂度就是O(NlogN).单个询问O(1)。改进方法
我们把一开始的N个数分块。每一块的大小为logN.然后O(N)扫得每一块的最小值Mi.然后对每一块都做一遍ST算法。再对Mi做一遍ST算法。那么预处理的时间复杂度就是O(NlogN∗logN+NlogN∗logN∗log(logN))=O(N+Nlog(logN)).接着对于一个询问,假设为l,r.设Blocki表示位置i所属的块。那么我们可以把一个询问分为三段。第一段为Blockl中l到结尾。第二段为Blockl+1→Blockr−1.第三段为Blockr中起点到r.
那么因为对于已经处理出ST表的地方可以O(1)完成询问。所以我们的询问也是O(1)的。
那么总的时间复杂度就是O(N+Nlog(logN)+Q)了。
代码
#include<cstdio> #include<cstring> #include<algorithm> #define max(a,b) (a > b ? a : b) using namespace std; const int MAXN = 10000005,LG = 25; int Log[MAXN],V[MAXN],F[LG][MAXN / 23 + 2],Ti[LG],N,Len; struct BLOCK { int F[5][LG],Back[LG],Front[LG],n; void Pre_Treat() { Front[0] = F[0][0]; for(int i = 1;i < n;++ i) Front[i] = max(Front[i - 1],F[0][i]); for(int i = n - 1;i + 1;-- i) Back[i] = max(Back[i + 1],F[0][i]); for(int i = 1,q = 2;i <= Log ;++ i,q <<= 1) for(int j = 0;j + q <= n;++ j) F[i][j] = max(F[i - 1][j],F[i - 1][j + (q >> 1)]); } int Query(int l,int r) { int p = Log[r - l + 1]; return max(F[p][l],F[p][r - Ti[p] + 1]); } }Block[MAXN / 23 + 2]; void read(int &x) { char c; while (c = getchar(),c < '0' || c > '9'); x = c - 48; while (c = getchar(),c >= '0' && c <= '9') x = x * 10 + c - 48; } int Query(int l,int r) { if (l > r) return 0; int p = Log[r - l + 1]; return max(F[p][l],F[p][r - Ti[p] + 1]); } int main() { read(N); for(int i = 0;i < N;i ++) read(V[i]); for(int i = 0,j = 1;i < LG;i ++,j <<= 1) Ti[i] = j; for(int i = 0,j = 1,k = 1;k <= N;k ++) if (k == j) Log[k] = i,i ++,j <<= 1; else Log[k] = i - 1; Len = Log ; BLOCK *a = Block; for(int i = 0,cur = 0;i < N;++ cur) { int lst = i,mx = 0; for(int c = Len;c && i < N;-- c,++ i) a->F[0][Len - c] = V[i],mx = max(V[i],mx); F[0][cur] = mx; a->n = i - lst + 1; a->Pre_Treat(); ++ a; } int all = (N - 1) / Len; for(int i = 1,q = 2;i <= Log[all];++ i,q <<= 1) for(int j = 0;j + q <= all;++ j) F[i][j] = max(F[i - 1][j],F[i - 1][j + (q >> 1)]); int M; read(M); for(int i = 1;i <= M;i ++) { int l,r; read(l),read(r); int b1 = l / Len,b2 = r / Len,p1 = l % Len,p2 = r % Len; if (b1 == b2) printf("%d\n", Block[b1].Query(p1,p2)); else { int a = Query(b1 + 1,b2 - 1),b = Block[b1].Back[p1],c = Block[b2].Front[p2]; b = max(b,c); printf("%d\n", max(a,b)); } } return 0; }
相关文章推荐
- HDU-3819-A and B Problem
- 证明ln2=0 和 2=1
- Qt4 inputpanel 升级改造
- android的理解之一——实现欢迎页面的跳转
- Iterator 模式
- 可以供MFC调用的,QT实现的DLL(使用qt-solutions的qtwinmigrate实现)
- 关于nandflash与norflash
- UI:文件操作、通知中心
- Shell Step by Step (3) —— Stdin & if
- Linux/Ubuntu下 静态编译Qt程序
- SearchView+RecyclerView+GreenDao的搜索功能实现(2)
- Spring的包结构解析
- 【约数倍数算法】——求最大公约数、最小公倍数
- 将String转换成Int数组-Java
- MySQL常见备份与恢复方案 推荐
- CF GYM100548 (相邻格子颜色不同的方案数 2014西安现场赛F题 容斥原理)
- Java多线程2:Thread中的实例方法
- 大型网站特点
- 函数的返回值
- HDU-3827-The Killers of Two Kingdoms