poj 3264 Balanced Lineup ST+线段树
来源:互联网 发布:mac破解软件大全下载 编辑:程序博客网 时间:2024/05/22 10:40
以下内容转自:http://www.cnblogs.com/cnjy/archive/2009/08/30/1556566.html
RMQ(Range Minimum/Maximum Query)问题:
RMQ问题是求给定区间中的最值问题。当然,最简单的算法是O(n)的,但是对于查询次数很多(设置多大100万次),O(n)的算法效率不够。可以用线段树将算法优化到O(logn)(在线段树中保存线段的最值)。不过,Sparse_Table算法才是最好的:它可以在O(nlogn)的预处理以后实现O(1)的查询效率。下面把Sparse Table算法分成预处理和查询两部分来说明(以求最小值为例)。
预处理:
预处理使用DP的思想,f(i, j)表示[i, i+2^j - 1]区间中的最小值,我们可以开辟一个数组专门来保存f(i, j)的值。
例如,f(0, 0)表示[0,0]之间的最小值,就是num[0], f(0, 2)表示[0, 3]之间的最小值, f(2, 4)表示[2, 17]之间的最小值
注意, 因为f(i, j)可以由f(i, j - 1)和f(i+2^(j-1), j-1)导出, 而递推的初值(所有的f(i, 0) = i)都是已知的
所以我们可以采用自底向上的算法递推地给出所有符合条件的f(i, j)的值。
查询:
假设要查询从m到n这一段的最小值, 那么我们先求出一个最大的k, 使得k满足2^k <(n - m + 1).
于是我们就可以把[m, n]分成两个(部分重叠的)长度为2^k的区间: [m, m+2^k-1], [n-2^k+1, n];
而我们之前已经求出了f(m, k)为[m, m+2^k-1]的最小值, f(n-2^k+1, k)为[n-2^k+1, n]的最小值
我们只要返回其中更小的那个, 就是我们想要的答案, 这个算法的时间复杂度是O(1)的.
例如, rmq(0, 11) = min(f(0, 3), f(4, 3))
由此我们要注意的是预处理f(i,j)中的j值只需要计算log(n+1)/log(2)即可,而i值我们也只需要计算到n-2^k+1即可。
http://162.105.81.212/JudgeOnline/problem?id=3264
经典的RMQ题
<pre name="code" class="plain">#include <iostream>#include <string>#include <math.h>using namespace std;#define maxs( a , b ) a>b?a:b#define mins( a , b ) a>b?b:aconst int MAX_N = 50005;int d[MAX_N];int dpmin[MAX_N][20];int dpmax[MAX_N][20];int n;void create_Dpmin(){ int i , j; for( i = 1 ; i <= n ; i++ ) dpmin[i][0] = d[i]; for( j = 1 ; j <= log((double)(n+1))/log(2.0) ; j++ ){ for( i = 1 ; i+(1<<j)-1 <= n ; i++ ){ dpmin[i][j] = mins( dpmin[i][j-1] , dpmin[i+(1<<(j-1))][j-1] ); } } }void create_Dpmax(){ int i , j; for( i = 1 ; i <= n ; i++ ) dpmax[i][0] = d[i]; for( j = 1 ; j <= log((double)(n+1))/log(2.0) ; j++ ){ for( i = 1 ; i+(1<<j)-1 <= n ; i++ ){ dpmax[i][j] = maxs( dpmax[i][j-1] , dpmax[i+(1<<(j-1))][j-1] ); } } }int getmax( int a , int b ){ int k = (int)(log((double)(b-a+1))/log(2.0)); return maxs( dpmax[a][k] , dpmax[b-(1<<k)+1][k] ); }int getmin( int a , int b ){ int k = (int)(log((double)(b-a+1))/log(2.0)); return mins( dpmin[a][k] , dpmin[b-(1<<k)+1][k] ); }void Init(){ create_Dpmin(); create_Dpmax(); }int main(){ freopen( "in.txt" , "r" , stdin ); int i , m , a , b; scanf("%d%d",&n,&m); for( i = 1 ; i <= n ; i++ ){ scanf("%d",&d[i]); } Init(); while( m-- ){ scanf("%d%d",&a,&b); printf("%d\n",getmax(a,b)-getmin(a,b)); } return 0; }
线段树:转自http://my.oschina.net/Alexanderzhou/blog/204056
解题思路:查询区间最大值/最小值之差,最基础的线段树应用。
代码:
#include <cstdio>
// 线段树为完全二叉树,因此可用 root * 2 和 root * 2 + 1
// 来求得左右孩子节点的位移
#define L(root) ((root) << 1)
#define R(root) (((root) << 1) + 1)
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
const
int
MAXN = 50001;
int
cows[MAXN];
int
maxn, minn;
struct
st {
// 左右区间
int
left, right;
// 区间最大、最小值
int
max, min;
} st[MAXN * 4];
// 建树
void
build(
int
root,
int
l,
int
r) {
// 区间为叶子节点时,初始化各值后返回
st[root].left = l, st[root].right = r;
if
(l == r) {
st[root].max = st[root].min = cows[l];
return
;
}
// 否则,递归构建左右节点
int
m = l + ((r - l) >> 1);
build(L(root), l, m);
build(R(root), m + 1, r);
st[root].max = MAX(st[L(root)].max, st[R(root)].max);
st[root].min = MIN(st[L(root)].min, st[R(root)].min);
}
// 查询
void
query(
int
root,
int
l,
int
r) {
// 查询范围与节点区间范围恰好重合
if
(st[root].left == l && st[root].right == r) {
maxn = MAX(maxn, st[root].max);
minn = MIN(minn, st[root].min);
return
;
}
// 否则,将区间一分为二
int
m = st[root].left + ((st[root].right - st[root].left) >> 1);
// 查询范围“落”在左子节点区间
if
(r <= m) {
query(L(root), l, r);
// 查询范围“落”在右子节点区间
}
else
if
(l > m) {
query(R(root), l, r);
// 左右子节点区间各有一部分被查询范围覆盖:
// 将查询范围一分为二,分别查询左右子节点
}
else
{
query(L(root), l, m);
query(R(root), m + 1, r);
}
}
int
main() {
int
N, Q;
while
(
scanf
(
"%d%d"
, &N, &Q) != EOF) {
for
(
int
i = 1; i <= N; ++i) {
scanf
(
"%d"
, &cows[i]);
}
build(1, 1, N);
int
l, r;
while
(Q--) {
scanf
(
"%d%d"
, &l, &r);
maxn = 0, minn = 0x7FFFFFFF;
query(1, l, r);
printf
(
"%d\n"
, maxn - minn);
}
}
return
0;
}
- poj 3264 Balanced Lineup ST+线段树
- Balanced Lineup-POJ - 3264-RMQ线段树/st表
- POJ 3264 Balanced Lineup(st或者线段树)
- 【POJ】3264 - Balanced Lineup(RMQ - ST算法 || 线段树)
- poj 3264 Balanced Lineup(线段树,ST算法)
- poj 3264 Balanced Lineup ST
- poj 3264 Balanced Lineup(ST)
- poj 3264 Balanced Lineup ST
- 线段树 ST算法 RMQ poj 3264 Balanced Lineup 解题报告
- POJ3264 Balanced Lineup 线段树|ST表
- poj 3264 Balanced Lineup rmq/线段树
- POJ 3264 Balanced Lineup RMQ / 线段树
- POJ 3264 Balanced Lineup 线段树基础
- poj 3264 Balanced Lineup[线段树,,水]
- 【线段树】 POJ 3264 Balanced Lineup
- poj 3264 Balanced Lineup 基础线段树
- poj 3264 Balanced Lineup(线段树)
- POJ 3264 Balanced Lineup 线段树
- SpringMVC环境的搭建
- 《大话数据结构》读书笔记之二叉堆基本操作(最大堆)
- Git 使用笔记
- Maximum Subarray
- 排序1:插入排序(直接插入排序)
- poj 3264 Balanced Lineup ST+线段树
- hdu 1394 Minimum Inversion Number
- 最长上升子序列(LIS)长度的O(n^2)与O(nlogn)算法
- iOS 监测应用是否是第一次打开&监测应用是否已经更新
- 高桥和低桥
- Merge Intervals
- Problem 8:Largest product in a series
- .NET配置文件
- 2012长春站K题 || hdu4430 枚举+二分