poj 3624 Balanced Lineup -【数据结构】- ST表

ST算法

应用:
假如我给你n个数,然后有m次询问,每次询问求一段区间,[l,r]上得极差。循环暴力跑一遍,很简单得对吧,但是我们稍微让n的值大一点,m的值也大一点,很容易就让你Time limit exceed。所以,本算法就是专门解决此类问题的,求一段区间上的最大值和最小值,其实也可以用线段树,但是这类题目线段树反而没有ST表快,而且线段树的实现很复杂,我现在还不会,QAQ。

实现思想

1.初始化+预处理:
就是一个dp,只不过这里进行一个优化,二进制的思想,每段存储20,21,22,……,2k。即dp[i][j]表示从第i位开始的2j个数的最大最小值。由此我们很容易明白dp[i][0]=arr[i]。然后对于后面的值,我们将一个区间分成两半,对于当前的dp,他的最大值就等于他前一半区间和后一半区间的最大值,即一个二分的思想。这点其实很容易想通(原谅我用了如此恶毒的语言),即递推式有dp[i][j]=max(dp[i][j-1],dp[i+(1<<j-1)][j-1]),这里的两个小于号,表示位运算中的移位,即1左移j-1位,表示2的j-1次幂。好了根据以上部分,我们初始化的代码可以写出来了

void init(){
	for(int i=1;i<=n;i++){
		dpmax[i][0]=a[i];
		dpmin[i][0]=a[i];
	}
	for(int j=1;(1<<j)<=n;j++){
		for(int i=1;i+(1<<j)-1<=n;i++){
			dpmax[i][j]=max(dpmax[i][j-1],dpmax[i+(1<<j-1)][j-1]);
			dpmin[i][j]=min(dpmin[i][j-1],dpmin[i+(1<<j-1)][j-1]);
		}
	}
}

我的代码写了两组dp,因为我们不光要求最大值,还要求最小值,计算极差。其实i,j上限不好理解,但是j很好理解,最多算到一个小于等于n数,i你可以理解为至少从i开始后面有一个数。j放在外层循环,因为我们每次要更新的就是区间上的最大值和最小值,而j代表着区间。

2.查询:
对于m次询问,我们每次输入一个区间l和r,用search函数来访问值。对于闭区间l,r长度就是r-l+1。我们另k=log2(r-l+1),则对应我们要访问的最大值就是kmax=max(dp[l][k],dp[r-(1<<k)+1][k])。即dp[l][k]维护的是[l, l + 2k- 1], dp[r - (1 << k) + 1][k]维护的是[r - 2 k+ 1, r] 。

int rmq(int l,int r){
	int k=(int)log2(r-l+1);
	int kmax,kmin;
	kmax=max(dpmax[l][k],dpmax[r-(1<<k)+1][k]);
	kmin=min(dpmin[l][k],dpmin[r-(1<<k)+1][k]);
	return kmax-kmin;
}

例题:
poj-3264:Balanced Lineup

Balanced Lineup

Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 72914 Accepted: 33553 Case Time Limit: 2000MS

Description

For the daily milking, Farmer John’s N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to organize a game of Ultimate Frisbee with some of the cows. To keep things simple, he will take a contiguous range of cows from the milking lineup to play the game. However, for all the cows to have fun they should not differ too much in height.

Farmer John has made a list of Q (1 ≤ Q ≤ 200,000) potential groups of cows and their heights (1 ≤ height ≤ 1,000,000). For each group, he wants your help to determine the difference in height between the shortest and the tallest cow in the group.

Input

Line 1: Two space-separated integers, N and Q.
Lines 2…N+1: Line i+1 contains a single integer that is the height of cow i
Lines N+2…N+Q+1: Two integers A and B (1 ≤ A ≤ B ≤ N), representing the range of cows from A to B inclusive.
Output

Lines 1…Q: Each line contains a single integer that is a response to a reply and indicates the difference in height between the tallest and shortest cow in the range.
Sample Input

6 3
1
7
3
4
2
5
1 5
4 6
2 2
Sample Output

6
3
0

ac代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<math.h>
#include<queue>
using namespace std;
#define N 100001
#define maxn 50004
typedef long long ll;
const int inf=0x3f3f3f3f;	
int n,m;
int a[maxn],dpmax[maxn][50],dpmin[maxn][50];
void init(){
	for(int i=1;i<=n;i++){
		dpmax[i][0]=a[i];
		dpmin[i][0]=a[i];
	}
	for(int j=1;(1<<j)<=n;j++){
		for(int i=1;i+(1<<j)-1<=n;i++){
			dpmax[i][j]=max(dpmax[i][j-1],dpmax[i+(1<<j-1)][j-1]);
			dpmin[i][j]=min(dpmin[i][j-1],dpmin[i+(1<<j-1)][j-1]);
		}
	}
}
int rmq(int l,int r){
	int k=(int)log2(r-l+1);
	int kmax,kmin;
	kmax=max(dpmax[l][k],dpmax[r-(1<<k)+1][k]);
	kmin=min(dpmin[l][k],dpmin[r-(1<<k)+1][k]);
	return kmax-kmin;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	init();
	while(m--){
		int l,r;
		scanf("%d%d",&l,&r);
		cout<<rmq(l,r)<<endl;
	}
	return 0;
}
发布了43 篇原创文章 · 获赞 56 · 访问量 5129

猜你喜欢

转载自blog.csdn.net/tran_sient/article/details/96891862
今日推荐