poj2823--Sliding Window--线段树||单调队列
2013-11-16 20:11
393 查看
Sliding Window
An array of size n ≤ 106 is given to you. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves rightwards by one position. Following is an example: The array is [1 3 -1 -3 5 3 6 7], and k is 3.
Input The input consists of two lines. The first line contains two integers n and k which are the lengths of the array and the sliding window. There are n integers in the second line. Output There are two lines in the output. The first line gives the minimum values in the window at each position, from left to right, respectively. The second line gives the maximum values. Sample Input 8 3 1 3 -1 -3 5 3 6 7 Sample Output -1 -3 -3 -3 3 3 3 3 5 5 6 7 Source POJ Monthly--2006.04.28, Ikki |
很裸的诶,插入点是O(logN),查询区间也是O(logN)就不多说了= =!
代码如下,
#include <iostream>
#include <algorithm>
#include <cstdio>
#define mid ((l+r)>>1)
#define lson (root<<1)
#define rson (root<<1|1)
using namespace std;
const int maxnum=1e6+100;
struct Node
{
int l,r;
int val;
int _max;
int _min;
}tree[3*maxnum];
void build_tree(int l,int r,int root)
{
tree[root].l=l;
tree[root].r=r;
if(l==r)
return;
else
{
build_tree(l,mid,lson);
build_tree(mid+1,r,rson);
}
}
void update_point(int value,int position,int root)
{
int l=tree[root].l;
int r=tree[root].r;
if(l==r)
{
tree[root].val=value;
tree[root]._max=value;
tree[root]._min=value;
}
else
{
if(position<=mid) update_point(value,position,lson);
else if(position>mid) update_point(value,position,rson);
tree[root]._max=max(tree[lson]._max,tree[rson]._max);
tree[root]._min=min(tree[lson]._min,tree[rson]._min);
}
}
int max_ans;
int min_ans;
bool flag;
void query_interval(int ql,int qr,int root)
{
int l=tree[root].l;
int r=tree[root].r;
if(l==ql&&r==qr)
{
if(flag)
{
max_ans=tree[root]._max;
min_ans=tree[root]._min;
flag=false;
}
else
{
max_ans=max(max_ans,tree[root]._max);
min_ans=min(min_ans,tree[root]._min);
}
}
else
{
if(qr<=mid)
{
query_interval(ql,qr,lson);
}
else if(ql>mid)
{
query_interval(ql,qr,rson);
}
else
{
query_interval(ql,mid,lson);
query_interval(mid+1,qr,rson);
}
}
}
int ans1[maxnum];
int ans2[maxnum];
int main()
{
//freopen("input.txt","r",stdin);
int n,k;
cin>>n>>k;
if(k>n) k=n;
build_tree(1,n,1);
for(int i=1;i<=n;++i)
{
int temp;
scanf("%d",&temp);
update_point(temp,i,1);
}
for(int i=1;i<=n-k+1;++i)
{
flag=true;
query_interval(i,i+k-1,1);
ans1[i]=min_ans;
ans2[i]=max_ans;
}
int i;
for(i=1;i<=n-k;++i)
printf("%d ",ans1[i]);
printf("%d\n",ans1[i]);
for(i=1;i<=n-k;++i)
printf("%d ",ans2[i]);
printf("%d\n",ans2[i]);
return 0;
}
第二种是O(N)的维护一个单调队列
很详尽的解题分析!
•对于序列{3,2,4,6,8,8,10,1,3,6}
•我们首先看前5个数
•3,2,4,6,8最小的为2
•那么对于3这样的数,存在还有什么意义呢?
•我们只需要2,4,6,8就足够了
•下次比较2,4,6,8,8就可以了,前一个8也是没有意义的,只保留2,4,6,8,答案为2
•下次我们的2也不能再保留了,2出队,剩下4,6,8,10,答案是4
•再下一次,1加入,4出队,那么前面的6,8,10活着还有什么意义?(为什么)全部出队!答案为1
•这时我们队列中只剩下1了,下一次加入3,答案还是为1,最后加入6,答案不变。
•我们看到利用双端队列我们维护了一个单调递增的序列(想想为什么),每次答案都是队首元素。
•出队的条件只有两个:
•1.它的位置超过了我们所求区间的限制。(队列头出队)
•2.它的存在没有意义。(队列尾出队)
由于每个元素入队出队的次数不会超过n,时间复杂度O(n)
以下是代码,居然WA了一炮!初始化要牢记在心啊!写每一步程序要去思考啊,你又一点都不聪明!:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxnum=1e6+100;
struct queue
{
int index;
int value;
};
queue min_ans[maxnum];
queue max_ans[maxnum];
int a[maxnum];
int main()
{
freopen("input.txt","r",stdin);
int n,k;
scanf("%d%d",&n,&k);
if(k>n) k=n;
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
}
int head=1,tail=1;
min_ans[1].value=a[1];
min_ans[1].index=1;
max_ans[1].value=a[1];
max_ans[1].index=1;
for(int i=2;i<=k;++i)
{
while(head<=tail&&a[i]<=min_ans[tail].value)
{
--tail;
}
++tail;
min_ans[tail].value=a[i];
min_ans[tail].index=i;
}
printf("%d",min_ans[head].value);
for(int i=k+1;i<=n;++i)
{
if(min_ans[head].index<=i-k) ++head; //进来啥都别想,一定要记得考虑出队情况!
while(head<=tail&&a[i]<=min_ans[tail].value)
{
--tail;
}
++tail;
min_ans[tail].value=a[i];
min_ans[tail].index=i;
printf(" %d",min_ans[head].value);
}
printf("\n");
head=tail=1;//初始化要牢记在心啊!
for(int i=2;i<=k;++i)
{
while(head<=tail&&a[i]>=max_ans[tail].value)
{
--tail;
}
++tail;
max_ans[tail].value=a[i];
max_ans[tail].index=i;
}
printf("%d",max_ans[head].value);
for(int i=k+1;i<=n;++i)
{
if(max_ans[head].index<=i-k) ++head; //进来啥都别想,一定要记得考虑出队情况!
while(head<=tail&&a[i]>=max_ans[tail].value)
{
--tail;
}
++tail;
max_ans[tail].value=a[i];
max_ans[tail].index=i;
printf(" %d",max_ans[head].value);
}
printf("\n");
return 0;
}
相关文章推荐
- 第二章 一切都是对象
- Merge join、Hash join、Nested loop join对比分析
- 【牛x】 find ./* | xargs grep "Invalid configuration"
- MongoDB主从复制实验 master/slave
- JS权威指南 读书笔记 第一章 JavaScript概述
- 数据结构教程第三章实验代码
- 小算法测试
- Linux没有最小只有更小----迷你Linux版本大集合
- 利用chrome浏览器的F12功能提取网页中的视频、音乐
- zoj3622Magic Number
- Intent的属性及Intent-filter配置——指定Action、Category调用系统Activity
- C语言变量、函数的作用域及变量的存储方式
- 复制构造函数
- Struts2在MyEclipse9.0上的一些错误
- JAVA学习.JAVA面向对象编程的理解&Random类
- cURL实现Get和Post
- 一步一步学Silverlight 2系列(12):数据与通信之WebClient
- NSIS打包发布Qt程序
- C语言写CGI程序
- 磁盘分区