标签:int 个数 opened namespace print str 图片 12px \n
利用了倍增的思想,st[i][j]表示[i, i + 2j - 1]的区间内的最(大、小)值
自然st[i][0]存的就是序列中的第i个数,区间[l, r]的长度为log2(r - l + 1)
预处理:
处理每个为2的倍数的区间:
区间 [i, i + 2j] 的值为区间 [i, i + 2j - 1] 和区间 [i + 2j - 1, i + 2j] 的最值
复杂度O(n log2 n)
关于每次取log2,用cmath里的函数会很慢(保留了小数)
所以可以预处理出log2(i)的整数值
for(int i = 0; (1 << i) <= n; i++) Log2[1 << i] = i; for(int i = 1; i <= n; i++) if(!Log2[i]) Log2[i] = Log2[i - 1];
查询[l, r]区间的最值:
取区间[l, l + 2k - 1]和区间[r - 2k + 1, r]的最值
复杂度O(1)
其实蛮好理解的...QwQ
【代码:】
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 using namespace std; 5 6 const int MAXN = 1e5 + 1, MAXM = 1e6 + 1; 7 const int K = 18; 8 9 int n, m; 10 int a[MAXN], st[MAXN][K], Log2[MAXN]; 11 12 int Query(int l, int r) { 13 int x = Log2[r - l + 1]; 14 return max(st[l][x], st[r - (1 << x) + 1][x]); 15 } 16 int main() { 17 scanf("%d%d", &n, &m); 18 for(int i = 1; i <= n; i++) scanf("%d", &a[i]); 19 for(int i = 1; i <= n; i++) st[i][0] = a[i]; 20 for(int j = 1; j <= K; j++) { 21 for(int i = 1; i + (1 << j) - 1 <= n; i++) 22 st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); 23 } 24 for(int i = 0; (1 << i) <= n; i++) 25 Log2[1 << i] = i; 26 for(int i = 1; i <= n; i++) 27 if(!Log2[i]) Log2[i] = Log2[i - 1]; 28 while(m--) { 29 int l, r; 30 scanf("%d%d", &l, &r); 31 printf("%d\n", Query(l, r)); 32 } 33 }
标签:int 个数 opened namespace print str 图片 12px \n
原文地址:https://www.cnblogs.com/devilk-sjj/p/9021574.html