Sliding Window(poj-2823)
Sliding Window
Time Limit: 12000MS Memory Limit: 65536K
Total Submissions: 67410 Accepted: 19122
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

题意:一排n个数字在宽为k(就是说每次能看见连续的k个数字)的窗户依次向右移动一位,问每次从窗户看到的数字中的最大,最小的数是什么。

思路:用线段树查询[i,i+m-1]的最大,最小值。

比赛时打线段是模板超时,又没能想出怎么优化代码,还是对线段树理解存在1模糊,才不能根据题意灵活运用,做出相应的,变通及优化。下来有对线段树做了理解。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N=1e6+10;

#define rson m+1,r,rt<<1|1
#define lson l,m,rt<<1
ll sum[N<<2],sum1[N<<2];
ll max(ll a,ll b)
{
    return a>b? a:b;
}
ll min(ll a,ll b)
{
    return a<b?a:b;
}
void PushUp(int rt)
{
    sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
    sum1[rt]=min(sum1[rt<<1],sum1[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        scanf("%I64d",&sum[rt]);
        sum1[rt]=sum[rt];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    PushUp(rt);
}
ll res=-inf;
ll res1=inf;
ll query1(int l,int r,int L,int R,int rt)
{
    if(L<=l&&r<=R) return sum[rt];
    int m=(l+r)>>1;
    if(R<=m) {res=max(res,query1(l,m,L,R,rt<<1));}
    else if(L>m) {res=max(res,query1(m+1,r,L,R,rt<<1|1));}
    else
    {
        res=max(res,query1(l,m,L,R,rt<<1));
        res=max(res,query1(m+1,r,L,R,rt<<1|1));
    }
    return res;
}
ll query2(int l,int r,int L,int R,int rt)
{

    if(L<=l&&r<=R) return sum1[rt];
    int m=(l+r)>>1;
    if(R<=m)res1=min(res1,query2(l,m,L,R,rt<<1));
    else if(L>m)res1=min(res1,query2(m+1,r,L,R,rt<<1|1));
    else
    {
        res1=min(res1,query2(l,m,L,R,rt<<1));
        res1=min(res1,query2(m+1,r,L,R,rt<<1|1));
    }
    return res1;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        memset(sum,0,sizeof(sum));
        memset(sum1,0,sizeof(sum1));
        build(1,n,1);
        for(int i=1;i<=n-m+1;i++)
        {
            res1=inf;
            if(i==1) printf("%I64d",query2(1,n,i,i+m-1,1));
            else printf(" %I64d",query2(1,n,i,i+m-1,1));
        }
        printf("\n");
        for(int i=1;i<=n-m+1;i++)
        {
            res=-inf;
            if(i==1) printf("%I64d",query1(1,n,i,i+m-1,1));
            else printf(" %I64d",query1(1,n,i,i+m-1,1));
        }
        printf("\n");
    }
    return 0;
}
  if(L<=l&&r<=R) return sum[rt];

之前我写的 return条件是     if(L==l&&r==R) return sum1[rt];  和  

                               if(l==r) {res1=min(res1,sum1[rt]);return res1;}超时了。

对比了俩个过程:



所以知道了if(L<=l&&r<=R) return sum[rt];还是可以省去了很多没必要得计算。如在[1,10]中找[1,6].第一次找到得[1,5]的sum[2]就不用在往下找了。

 if(R<=m)res1=min(res1,query2(l,m,L,R,rt<<1));
    else if(L>m)res1=min(res1,query2(m+1,r,L,R,rt<<1|1));

查询中这个范围的由来:为什么是R<=m,L>m不是R<=m,L>=m,也不是R<m,L>m.?在[5,8]里找[5,6],m=6;就不用往[5,8]的右儿子找了。在[1,4]里找[2,4],m=2,2属于左儿子,还需要在[1,4]的左儿子中找。


阅读更多
个人分类: 线段树
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

Sliding Window(poj-2823)

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭