51Nod 1174:区间中最大的数
来源:互联网 发布:4k电视直播软件 编辑:程序博客网 时间:2024/05/20 23:37
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1174
区间最大值查询,挺简单的,原来学习了线段树,很容易可以解决这个问题,不过看到
别人用ST(Sparse Table)算法来解决这个问题,这个没学过,比较好奇就看了一下。
过程也挺简单的,就是动态规划的思想。有一个dp数组。
dp[i][j] 维护的是 【i , i + 2^j - 1】这个区间的最大/最小值,
则dp[i][0] 维护的是【i, i + 2^0 -1】 = 【 i , i 】的最大/最小值。
因此dp[i][0] = a[i]
而dp[i][j] = max/min【i , j】 = max/min(dp【 i , j-1】,dp【 i + (1<<(j-1)) , j-1】
其意义如下图所示:
i ~ ( i + 2^j -1 ) 中有2^j次方个数,我们可以把这整个区间分成2个拥有2^j-1次方个数的区间。
所以dp[i][j] 是由【 i , i + 2^(j-1)-1 】和 【i+2^(j-1),i+2^j-1-1】
第一个区间就是dp[i][j-1] ,第二个区间是dp[i+2^(j-1)][j-1]。
查询的时候,假如想要left,right的最大值或最小值,时间复杂度是0(1)。
我们知道left,right区间里面由right-left + 1.
而right不恰好是 i + 2^j - 1对应的数,因此这时我们求解的时候区间应该重叠。
我们找最大的k 2^k <= (right-left+1) k = ceil(log(right-left+1))
则整个区间[left,right]可由两个区间 [left,left + 2^k -1] 和 [right-2^k+1][right]并起来构成
则区间的最大最小值就是 max/min(dp[left][k],dp[right-(1<<k)+1][k])得到。
对应如下图所示:
AC代码:ST算法
#include <iostream>#include <stdio.h>#include <string.h>#include <math.h>using namespace std;const int maxn = 10005;int dp[maxn][32];void init(int N){ for(int i = 0; i < N; i++) { scanf("%d",&dp[i][0]); } for(int j = 1; j < 32; j++) for(int i = 0; i < N; i++) { if(i+(1<<(j-1))>=N) break; ///越界 dp[i][j] = max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); }}int query(int left,int right){ int k = (int)log2(right-left+1.0); int ans = max(dp[left][k],dp[right-(1<<k)+1][k]); return ans;}int main(){ int N,Q; while(~scanf("%d",&N)) { init(N); scanf("%d",&Q); int i,j; while(Q--) { scanf("%d%d",&i,&j); printf("%d\n",query(i,j)); } } return 0;}
AC代码:线段树
#include <iostream>#include <stdio.h>#include <string.h>#include <math.h>#define lchild left,mid,root<<1#define rchild mid+1,right,root<<1|1using namespace std;const int maxn = 10005;int Max[maxn<<2];void push_up(int root){ Max[root] = max(Max[root<<1],Max[root<<1|1]);}void build(int left,int right,int root){ if(left == right) { scanf("%d",&Max[root]); return; } int mid = (left+right)>>1; build(lchild); build(rchild); push_up(root);}int query(int L,int R,int left,int right,int root){ if(L<=left && right<=R) return Max[root]; int mid = (left+right)>>1; int ans = 0; if(L <= mid) ans = max(ans,query(L,R,lchild)); if(R > mid) ans = max(ans,query(L,R,rchild)); return ans;}int main(){ int N,Q; while(~scanf("%d",&N)) { memset(Max,0,sizeof(Max)); build(1,N,1); scanf("%d",&Q); int i,j; while(Q--) { scanf("%d%d",&i,&j); int ans = query(i+1,j+1,1,N,1); printf("%d\n",ans); } } return 0;}
- 51nod 1174 区间中最大的数【线段树】
- 51nod 1174 区间中最大的数
- 51nod--1174 区间中最大的数 (RMQ)
- 【51Nod】1174 - 区间中最大的数(RMQ)
- 51nod 1174 区间中最大的数(线段树)
- 51nod 1174 区间中最大的数
- 51nod:1174 区间中最大的数(RMQ)
- 【51Nod】1174 区间中最大的数
- 51Nod 1174区间中最大的数
- 51Nod-1174-区间中最大的数
- 51Nod 1174 区间中最大的数 线段树
- 51Nod-1174-区间中最大的数
- 51Nod-1174 区间中最大的数(RMQ)
- 51Nod 1174:区间中最大的数
- 51Nod 1174 区间中最大的数<线段树>
- 51nod 1174 区间中最大的数(RMQ)
- 51nod 1174 区间中最大的数
- 51Nod-1174-区间中最大的数
- mybatis一、二级缓存详解
- 数据结构 KMP next数组
- linux把运行中的指令暂停或挂到后台运行
- 关于typedef的用法总结
- 如何将一个进程(线程)绑定到一个固定的CPU核上?——004
- 51Nod 1174:区间中最大的数
- 三角形兼梯形布局
- Oracle11g安装问题汇总
- 初学JAVA笔记(一)
- Quartz-JobDetail和Trigger-Job
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- 反射
- win10 离线安装.net framework 3.5并且无法安装错误代码0x800F081F
- Mysql存储过程