PKU 2823 Sliding Window(线段树||RMQ||单调队列)
题目大意:原题链接(定长区间求最值)
给定长为n的数组,求出每k个数之间的最小/大值。
解法一:线段树
segtree节点存储区间的最小/大值
Query_min(int p,int l,int r,int ll,int rr)从编号为p的节点开始在区间[l,r]内查询区间[ll,rr]的最小值
Query_max(int p,int l,int r,int ll,int rr)从编号为p的节点开始在区间[l,r]内查询区间[ll,rr]的最大值
当[l,r]区间完全包含于[ll,rr]区间时,直接return segmin[p]或者return segmax[p].
注意:
1.这两个递归调用时,传入的参数ll和rr始终没有变;
2.这两个函数中的if(rr>mid)不能取"=",比如在区间[1,8]内查询区间[1,4]的最值,因为if(ll<=mid)已经把区间[1,4]的结果给计算出来了,如果加上"=",那么接下来就要在区间[5,8]内查询区间[1,4]的最值了,而区间[1,4]始终<区间[5,8]内的mid,导致程序无法return,崩溃;
3.这两个函数中的int begin=inf;int end=inf;语句和int begin=-inf;int end=-inf语句很关键,比如在区间[1,8]查询内查询区间[1,5]的最值,因为1<=1<=4<=4如上所述区间[1,4]完全包含于区间[1,4];所以区间[1,4]的最值正常返回给begin或者end,但是如果每次递归调用时不重新给begin和end赋值的话,那么叶子节点[5]的值无法正常返回,因为叶子节点[5]返回的值无法和begin或者end比较大小.因为begin和end根本就没有值.

#include<cstdio>
#include<algorithm>
#define maxn 1000005
#define inf 0x3f3f3f3f
using namespace std;
int Segmin[maxn<<],Segmax[maxn<<];
int n,k,value; void Build(int p,int l,int r)
{
if(l==r){
scanf("%d",&value);
Segmax[p]=Segmin[p]=value;
return;
}
int mid=(l+r)/;
Build(*p,l,mid);
Build(*p+,mid+,r);
Segmin[p]=min(Segmin[*p],Segmin[*p+]);
Segmax[p]=max(Segmax[*p],Segmax[*p+]);
}
int Query_min(int p,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr)
return Segmin[p];
int mid=(l+r)/;
int begin=inf,end=inf;
if(ll<=mid)
begin=Query_min(*p,l,mid,ll,rr);
if(rr>mid)
end=Query_min(*p+,mid+,r,ll,rr);
return min(begin,end);
}
int Query_max(int p,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr)
return Segmax[p];
int mid=(l+r)/;
int begin=-inf,end=-inf;
if(ll<=mid)
begin=Query_max(*p,l,mid,ll,rr);
if(rr>mid)
end=Query_max(*p+,mid+,r,ll,rr);
return max(begin,end);
} int main()
{
scanf("%d%d",&n,&k);
Build(,,n);
for(int i=;i<=n-k+;i++)
printf("%d ",Query_min(,,n,i,i+k-));
printf("\n");
for(int i=;i<=n-k+;i++)
printf("%d ",Query_max(,,n,i,i+k-));
printf("\n");
}
#include<cstdio>
#include<algorithm>
#define maxn 1000005
#define inf 0x3f3f3f3f
using namespace std;
int segmin[maxn<<],segmax[maxn<<];
int n,k,value,mi,ma; void Build(int p,int l,int r)
{
if(l==r){
scanf("%d",&value);
segmax[p]=segmin[p]=value;
return;
}
int mid=(l+r)/;
Build(*p,l,mid);
Build(*p+,mid+,r);
segmin[p]=min(segmin[*p],segmin[*p+]);
segmax[p]=max(segmax[*p],segmax[*p+]);
}
void Query_val(int p,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr){
mi=min(mi,segmin[p]);
ma=max(ma,segmax[p]);
return;
}
int mid=(l+r)/;
if(ll<=mid)
Query_val(*p,l,mid,ll,rr);
if(rr>mid)
Query_val(*p+,mid+,r,ll,rr);
} int main()
{
scanf("%d%d",&n,&k);
Build(,,n);
for(int i=;i<=n-k+;i++){
mi=inf,ma=-inf;
Query_val(,,n,i,i+k-);
printf("%d ",mi);
}
printf("\n");
for(int i=;i<=n-k+;i++){
mi=inf,ma=-inf;
Query_val(,,n,i,i+k-);
printf("%d ",ma);
}
printf("\n");
}
解法二:RMQ
因为是定长区间,所以数组d[maxn]被优化,只剩下一维.
#include<cstdio>
#include<algorithm>
#define maxn 1000007
using namespace std;
int c[maxn],d[maxn];
int n,k,t=;
//d[i]表示从i到i+k-1的一段元素中的最小值
void Init1()
{
for(int i=;i<=n;i++)
d[i]=c[i];
for(int j=;j<=t;j++){//j<=t或者(1<<j)<=k
for(int i=;i+(<<j)-<=n;i++)
d[i]=min(d[i],d[i+(<<(j-))]);
}
}
void Init2()
{
for(int i=;i<=n;i++)
d[i]=c[i];
for(int j=;j<=t;j++)
for(int i=;i+(<<j)-<=n;i++)
d[i]=max(d[i],d[i+(<<(j-))]);
} int Query1(int l,int r){
return min(d[l],d[r-(<<t)+]);
}
int Query2(int l,int r){
return max(d[l],d[r-(<<t)+]);
} int main()
{//定长区间(长度为k)查找
scanf("%d%d",&n,&k);
while(<<(t+)<=k) t++;
for(int i=;i<=n;i++)
scanf("%d",&c[i]);
Init1();
for(int i=;i<=n-k+;i++){
if(i!=n-k+)
printf("%d ",Query1(i,i+k-));
else
printf("%d\n",Query1(i,i+k-));
}
Init2();
for(int i=;i<=n-k+;i++){
if(i!=n-k+)
printf("%d ",Query2(i,i+k-));
else
printf("%d\n",Query2(i,i+k-));
}
}
解法三:单调队列
#include<cstdio>
#define maxn 1000005
using namespace std;
struct Que
{
int value;
int index;
}min_que[maxn],max_que[maxn]; int n,k,front,rear,num[maxn];
int max_rear_inc(int f,int r,int d)
{//递增队列,队尾插队
int mid;
while(f<=r){
mid=(f+r)/;
if(min_que[mid].value==d)
return mid;
else if(min_que[mid].value>d)
r=mid-;
else
f=mid+;
}
return f;
}
int min_rear_inc(int f,int r,int d)
{//递减队列,队尾插队
int mid;
while(f<=r){
mid=(f+r)/;
if(max_que[mid].value==d)
return mid;
else if(max_que[mid].value>d)
f=mid+;
else
r=mid-;
}
return f;
}
int main()
{
//while(scanf("%d%d",&n,&k)!=EOF){
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++)
scanf("%d",&num[i]); min_que[].value=num[];
min_que[].index=;
front=,rear=;
for(int i=;i<=k;i++){
rear=max_rear_inc(front,rear,num[i]);
min_que[rear].value=num[i];
min_que[rear].index=i;
}
printf("%d ",min_que[].value);
for(int i=k+;i<=n;i++){
rear=max_rear_inc(front,rear,num[i]);
min_que[rear].value=num[i];
min_que[rear].index=i;
if(min_que[front].index<=i-k)
front++;
printf("%d ",min_que[front].value);
}
printf("\n"); max_que[].value=num[];
max_que[].index=;
front=,rear=;
for(int i=;i<=k;i++){
rear=min_rear_inc(front,rear,num[i]);
max_que[rear].value=num[i];
max_que[rear].index=i;
}
printf("%d ",max_que[].value);
for(int i=k+;i<=n;i++){
rear=min_rear_inc(front,rear,num[i]);
max_que[rear].value=num[i];
max_que[rear].index=i;
if(max_que[front].index<=i-k)
front++;
printf("%d ",max_que[front].value);
}
printf("\n");
//}
return ;
}
#include<cstdio>
using namespace std;
#define maxn 2000005
int n,k;
int mq_min[maxn],mq_max[maxn],pos[maxn],c[maxn];
void get_Min()
{//递增队列
int front=,rear=;
for(int i=;i<k;i++){
while(front<=rear&&mq_max[rear]>=c[i])
rear--;
rear++;
mq_max[rear]=c[i];//新添加的为较大值
pos[rear]=i;
}
for(int i=k;i<=n;i++){
while(front<=rear&&mq_max[rear]>=c[i])
rear--;
rear++;
mq_max[rear]=c[i];
pos[rear]=i;
while(pos[front]<=i-k)
front++;
printf("%d ",mq_max[front]);
}
}
void get_Max()
{//递减队列
int front=,rear=;
for(int i=;i<k;i++){
while(front<=rear&&mq_min[rear]<=c[i])
rear--;
rear++;
mq_min[rear]=c[i];//新添加的为较小值
pos[rear]=i;
}
for(int i=k;i<=n;i++){
while(front<=rear&&mq_min[rear]<=c[i])
rear--;
rear++;
mq_min[rear]=c[i];
pos[rear]=i;
while(pos[front]<=i-k)
front++;
printf("%d ",mq_min[front]);
}
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++)
scanf("%d",&c[i]);
get_Min();
printf("\n");
get_Max();
}
PKU 2823 Sliding Window(线段树||RMQ||单调队列)的更多相关文章
- POJ 2823 Sliding Window 线段树
http://poj.org/problem?id=2823 出太阳啦~^ ^被子拿去晒了~晚上还要数学建模,刚才躺在床上休息一下就睡着了,哼,还好我强大,没有感冒. 话说今年校运会怎么没下雨!!!说 ...
- POJ 2823 Sliding Window 线段树区间求和问题
题目链接 线段树区间求和问题,维护一个最大值一个最小值即可,线段树要用C++交才能过. 注意这道题不是求三个数的最大值最小值,是求k个的. 本题数据量较大,不能用N建树,用n建树. 还有一种做法是单调 ...
- ACM学习历程—HDU 5289 Assignment(线段树 || RMQ || 单调队列)
Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered fro ...
- POJ 2823 Sliding Window (模板题)【单调队列】
<题目链接> <转载于>>> > 题目大意: 给你一段序列和一个长为k的窗口,这个窗口从最左边逐渐向右滑,直到滑到最右边,问你,该窗口在滑动的过程中,最大值和 ...
- bzoj 1171 并查集优化顺序枚举 | 线段树套单调队列
详见vfleaking在discuss里的题解. 收获: 当我们要顺序枚举一个序列,并且跳过某些元素,那么我们可以用并查集将要跳过的元素合并到一起,这样当一长串元素需要跳过时,可以O(1)跳过. 暴力 ...
- 1304F2 - Animal Observation (hard version) 线段树or单调队列 +DP
1304F2 - Animal Observation (hard version) 线段树or单调队列 +DP 题意 用摄像机观察动物,有两个摄像机,一个可以放在奇数天,一个可以放在偶数天.摄像机在 ...
- POJ 2823 线段树 Or 单调队列
时限12s! 所以我用了线段树的黑暗做法,其实正解是用单调队列来做的. //By SiriusRen #include <cstdio> #include <cstring> ...
- TTTTTTTTTTTTTT CDOJ Sliding Window 线段树(nlogn)或双端队列(n) 模板
题目链接: L - Sliding Window Time Limit:6000MS Memory Limit:131072KB 64bit IO Format:%lld & ...
- 【HDU6701】Make Rounddog Happy【权值线段树+双向单调队列】
题意:给你一个序列,求满足要求的子序列个数,其中要求为: 1.子序列的max-子序列长度len<=k 2.子序列中不出现重复的数字 题解:首先看到子序列max,很容易想到枚举最大值然后分治,这个 ...
随机推荐
- 运动目标检测ViBe算法
一.运动目标检测简介 视频中的运动目标检测这一块现在的方法实在是太多了.运动目标检测的算法依照目标与摄像机之间的关系可以分为静态背景下运动检测和动态背景下运动检测.先简单从视频中的背景类型来讨论. ...
- P2483 [SDOI2010]魔法猪学院
P2483 [SDOI2010]魔法猪学院 摘要 --> 题目描述 iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世 ...
- apacheserver全局配置具体解释
server标识相关指令: ServerName ServerAdmin ServerSignature ServerTokens UseCanonicalName UseCanonicalPhysi ...
- CSDN日报20170411 ——《怎样给自己的私活项目标价》
[程序人生]怎样给自己的私活项目标价 作者:瞬息之间 非常早之前讲过我们"怎么接私活的心得技巧".相信非常多同学听了心里痒痒的.据我认识的(无论是现实生活还是网上接触的)朋友来看. ...
- Spring_day02--AOP概念、原理、操作术语
AOP概念 hibernate要手动进行事务操作,在spring中通过配置文件来配置事务 1 aop:面向切面(方面)编程,扩展功能不修改源代码实现 2 AOP采取横向抽取机制,取代了传统纵向继承体 ...
- Unreal新建C++类或C++项目失败
出现以下错误: ... UnrealBuildTool Exception: System.UnauthorizedAccessException.... ... 是C盘无法访问权限的错误,请参考上一 ...
- Zabbix-3.0.0 安装Graphtree
导读 Zabbix中,想要集中展示图像,唯一的选择是screen,后来zatree解决了screen的问题,但性能不够好.Graphtree 由OneOaaS开发并开源出来,用来解决Zabbix的图形 ...
- 模拟window桌面实现
正在开发中的游戏有个全屏功能--可以在window桌面背景上运行,就像一些视频播放器在桌面背景上播放一样的,花了个上午整了个Demo放出来留个纪念. 实现功能:显示图标,双击图标执行相应的程序,右击图 ...
- 文艺青年、普通青年、2b青年到底是什么意思?
文艺青年.普通青年.2b青年到底是什么意思? 文艺青年就是脑子里跟别人想的不一样,思维跟人家相反或者另类的人. 普通青年呢就是像你一样,普普通通的. 2B青年就是黑铅笔青年,做事比较搞怪,古怪到让你哭 ...
- 160328、rabbitMQ集群部署示例
环境:Centos 6.5 x86_64MQ网址:http://www.rabbitmq.com/SERVER101\SERVER102 SERVER103 一.单节点安装 #yum install ...