POJ 3264 Balanced Lineup【RMQ附模板】

题目:http://poj.org/problem?id=3264

输入n和m组,接着n个数,然后是每组的区间下标范围,求这个区间内的最大与最小的差


参考好多:

http://blog.sina.com.cn/s/blog_9ec86af101013o84.html
http://www.cnblogs.com/whatbeg/p/3582486.html
http://www.myext.cn/other/a_7364.html

http://baike.baidu.com/view/1536346.htm

RMQ 1813MS    O(nlogn)预处理 O(1)应答

dp[i][j]表示从i号元素开始2^j个元素间的最值

dp[i][j-1] 表示[i,i+2^(j-1)-1]

dp[i+(1<<(j-1))][j-1] 表示[i+2^(j-1),i+2^j-1]

ST算法:

#include<iostream>
#include<cmath>
using namespace std;
#define max_(a,b) ((a)>(b)?(a):(b))
#define min_(a,b) ((a)>(b)?(b):(a))
int h[51005];
int maxdp[51001][20],mindp[51001][20];
int n,m;
void Init()
{
	int i,j,t;
	for(i=1;i<=n;i++)
	{
		maxdp[i][0] = h[i];
		mindp[i][0] = h[i];
	}
	for(j=1; (1<<j) <=n; j++)
	{
		for(i=1; i+(1<<j)-1<=n; i++)
		{
			t = i + (1 << (j-1));	//注意+比<<优先级高
			maxdp[i][j] = max_(maxdp[i][j-1],maxdp[t][j-1]);
			mindp[i][j] = min_(mindp[i][j-1],mindp[t][j-1]);
		}
	}
}
			
int rmq(int l,int r)
{
	int k,mx,my;
	k=(int)(log(r-l+1.0)/log(2.0));
	mx = max_(maxdp[l][k],maxdp[r-(1<<k)+1][k]);
	my = min_(mindp[l][k],mindp[r-(1<<k)+1][k]);
	return mx-my;
}
int main()
{
    int l,r,i;
//	freopen("a.txt","r",stdin);
	int rmp(int l,int r);
    while(~scanf("%d%d",&n,&m))
    {
        for( i=1;i<=n;i++) scanf("%d",&h[i]);
        Init();
        for( i=0;i<m;i++)
        {
            scanf("%d%d",&l,&r);
            printf("%d\n",rmq(l,r));
        }
    }
    return 0;
}


线段树:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define INF 0x7FFFFFFF
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define CLR( a , x ) memset ( a , x , sizeof (a) )
#define RE freopen("1.in","r",stdin)
#define WE freopen("1.out","w",stdout)

#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)>(b)?(b):(a))

#define MAX 50001
int ans1,ans2;  //整体的最大最小
int a[MAX];

struct node
{
    int l,r;        //i结点的区间范围
    int nMax,nMin;  //[l,r]的最值
}tree[MAX*4];
void build(int i,int l,int r)   //在结点i处建立[l,r]的区间
{
    tree[i].l = l;
    tree[i].r = r;
    if(l == r)    //叶结点
    {
        tree[i].nMax = tree[i].nMin = a[l];
        return;
    }
    int mid = (l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    tree[i].nMax = max(tree[i<<1].nMax,tree[i<<1|1].nMax);
    tree[i].nMin = min(tree[i<<1].nMin,tree[i<<1|1].nMin);
}
void query(int i,int l,int r)       //在i号结点查询[l,r]
{
    if(tree[i].l == l && tree[i].r == r)    //完全覆盖了
    {
        ans1 = max(tree[i].nMax,ans1);
        ans2 = min(tree[i].nMin,ans2);
        return;
    }
    int mid = (tree[i].l+tree[i].r)>>1;
    if(r <= mid)        //被查询的区间被含于i结点左区间,就去左子树找该区间
        query(i<<1,l,r);
    else if(l > mid)    //右子树找该区间
        query(i<<1|1,l,r);
    else    //  l<=mid && r>mid [l,r各在一边],[l,mid]在做左子树找
    {
        query(i<<1,l,mid);
        query(i<<1|1,mid+1,r);
    }
}

int main()
{
    int n,m,l,r;
   // RE;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i = 1; i <= n;i++)
            scanf("%d",&a[i]);
        build(1,1,n);
        REP(i,m)
        {
            scanf("%d%d",&l,&r);
            ans1 = -INF;
            ans2 = INF;
            query(1,l,r);
            printf("%d\n",ans1-ans2);
        }
    }
	return 0;
}

ST模板

	
#include <stdio.h>		
#include <math.h>
#define MIN 30
#define MAX 50050
int n,m,arr[MAX];
int maxdp[MAX][MIN],mindp[MAX][MIN]; 	
int RMQ(int x,int y,int flag);

int max_m(int a,int b)
{
	return a>b?a:b;
}
int min_m(int a,int b)
{
	return a>b?b:a;
}

void Create(int flag)
{				//flag = 0建立最大rmq,flag = 1最小
	int i,j,t;
    if (flag == 0) 
	{
        for (i = 1; i <= n; ++i)
            maxdp[i][0] = arr[i];
        for (j = 1; (1<<j) <= n; ++j)
            for (i = 1; i+(1<<j)-1 <= n; ++i)
			{
				t = i + ( 1 << (j-1) );
                maxdp[i][j] = max_m(maxdp[i][j-1],maxdp[t][j-1]);
			}
    }
    else 
	{
        for (i = 1; i <= n; ++i)
            mindp[i][0] = arr[i];
        for (j = 1; (1<<j) <= n; ++j)
            for (i = 1; i+(1<<j)-1 <= n; ++i)
			{
				t = i + ( 1 << (j-1) );
				mindp[i][j] = min_m(mindp[i][j-1],mindp[t][j-1]);
			}
    }
}

int RMQ(int l,int r,int flag)
{				//flag = 0查询最大rmq,flag = 1最小
    int k = (int)(log(r-l+1.0)/log(2.0));
    if (flag == 0)
		  return max_m(maxdp[l][k],maxdp[r-(1<<k)+1][k]);
    else
		return	min_m(mindp[l][k],mindp[r-(1<<k)+1][k]);
}

int main()
{
    int i,j,k;
    scanf("%d%d",&n,&m);
    for (i = 1; i <= n; ++i)
        scanf("%d",&arr[i]);

   	Create(1);
	Create(0);
    for (i = 1; i <= m; ++i) {
        scanf("%d%d",&j,&k);
        printf("%d\n",RMQ(j,k,0) - RMQ(j,k,1));
    }
}

/*	//若数组从0开始,其他不变
void Init(){			
	int i,j,t;
    for (i = 0; i < n; ++i)
        mindp[i][0] =h[ i];
    for (j = 1; (1<<j) <= n; ++j){
		for (i = 0; i+(1<<j)-1 < n; ++i){
			t = i + ( 1 << (j-1) );
			mindp[i][j] = min_m(mindp[i][j-1],mindp[t][j-1]);
		}
	}
}
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值