您的位置:首页 > 其它

poj2823--Sliding Window--线段树||单调队列

2013-11-16 20:11 393 查看
Sliding Window

Time Limit: 12000MS Memory Limit: 65536K
Total Submissions: 33661 Accepted: 9985
Case Time Limit: 5000MS
Description

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.
Window positionMinimum valueMaximum value
[1  3  -1] -3  5  3  6  7 -13
 1 [3  -1  -3] 5  3  6  7 -33
 1  3 [-1  -3  5] 3  6  7 -35
 1  3  -1 [-3  5  3] 6  7 -35
 1  3  -1  -3 [5  3  6] 7 36
 1  3  -1  -3  5 [3  6  7]37
Your task is to determine the maximum and minimum values in the sliding window at each position. 

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: