51Nod1174 区间中最大的数(学习线段树)

题目链接:
给出一个有N个数的序列,编号0 - N - 1。进行Q次查询,查询编号i至j的所有数中,最大的数是多少。
例如: 1 7 6 3 1。i = 1, j = 3,对应的数为7 6 3,最大的数为7。(该问题也被称为RMQ问题)
Input
第1行:1个数N,表示序列的长度。(2 <= N <= 10000)
第2 - N + 1行:每行1个数,对应序列中的元素。(0 <= S[i] <= 10^9)
第N + 2行:1个数Q,表示查询的数量。(2 <= Q <= 10000)
第N + 3 - N + Q + 2行:每行2个数,对应查询的起始编号i和结束编号j。(0 <= i <= j <= N - 1)
Output
共Q行,对应每一个查询区间的最大值。
Input示例
5
1
7
6
3
1
3
0 1
1 3
3 4
Output示例
7
7
3


线段树学习入门:http://blog.csdn.net/x314542916/article/details/7837276

线段树相关题型:http://blog.csdn.net/yrhsilence/article/details/5793699


<span style="font-size:24px;">#include"stdio.h"
#include"stdlib.h"
#include"math.h"
#include"algorithm"
#include"iostream"
#include"string.h"
const int maxn=10000+5;
int  maxv[maxn*3];
int  data[maxn];
int  n;
int max(int a,int b)
{ return a>b?a:b;}
void build(int node,int begin,int end)
{
	if(begin==end)
	    maxv[node]=data[begin];
	else{
		int m=(begin+end)/2;
		build(2*node,begin,m); //建立左子树 
		build(2*node+1,m+1,end);//建立右子树
		if(maxv[2*node]>=maxv[2*node+1])
		    maxv[node]=maxv[2*node];
		else
		    maxv[node]=maxv[2*node+1]; 
	}
}
int  query(int k,int L,int R,int ql,int qr)
{
	if(ql<=L&&R<=qr)
	   return maxv[k];
	int m=L+(R-L)/2;    //左子树的区间右继  eg:(1 8) 左(1 4) 右(5 8)  求的结果是 4   
	int ans=-1;
	if(ql<=m)  ans=max(ans,query(k*2,L,m,ql,qr));
	if(qr>m)   ans=max(ans,query(k*2+1,m+1,R,ql,qr));
	return ans;
}
void Updata(int k,int L,int R,int p,int v)  //修改data[p]=v 
{
	int m=L+(R-L)/2;
	if(L==R)  maxv[k]=v; //只有一个节点,叶子节点 
	else
	{
		//L<R 先递归更新左子树
		if(p<=m)
		    Updata(k*2,L,m,p,v);
		else
		   Updata(k*2+1,m+1,R,p,v);
		maxv[k]=max(maxv[k*2],maxv[k*2+1]); 
	} 
}
void print()
{
	for(int i=1;i<2*n;i++)
	   printf("%d ",maxv[i]);
	printf("\n");
 } 
int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d",&data[i]);
	build(1,0,n-1);
	int T;
	scanf("%d",&T);  //T次查询 
	while(T--)
	{
		int ql,qr;
		scanf("%d%d",&ql,&qr);
		printf("%d\n",query(1,0,n-1,ql,qr));
	}
	return 0;
} </span>




RMQ

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;

const int MAXN = 10010;
int dp[MAXN][20];
int mm[MAXN];
//初始化RMQ, b数组下标从1开始,从0开始简单修改
void initRMQ(int n,int b[])
{
    mm[0] = -1;
    for(int i = 1; i <= n; i++)
    {
        mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
        dp[i][0] = b[i];
    }
    for(int j = 1; j <= mm[n]; j++)
        for(int i = 1; i + (1<<j) -1 <= n; i++)
            dp[i][j] = max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
//查询最大值
int rmq(int x,int y)
{
    int k = mm[y-x+1];
    return max(dp[x][k],dp[y-(1<<k)+1][k]);
}
int main()
{
    int n;
    int b[MAXN];
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",b+i);
    initRMQ(n,b);
    int m;scanf("%d",&m);
    while(m--)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        int ans=rmq(x+1,y+1);
        printf("%d\n",ans);
    }
    return 0;
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值