Poj 2823 Sliding Window (单调队列 or 线段树)

题目在此


先贴线段树吧,就是查询区间的最大值最小值;

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 1000010

struct
{
    int l,r,mx,mi;
}root[N*6];
int n,k,a[N];

void update(int t)
{
    root[t].mx=max(root[t*2].mx,root[t*2+1].mx);
    root[t].mi=min(root[t*2].mi,root[t*2+1].mi);
}

void build(int t,int l,int r)
{
    root[t].l=l;
    root[t].r=r;
    if(l==r)
    {
        root[t].mx=root[t].mi=a[l];
        return;
    }
    int m=(l+r)>>1;
    build(t*2,l,m);
    build(t*2+1,m+1,r);
    update(t);
}

int query_mx(int t,int x,int y)
{
    int l=root[t].l,r=root[t].r;
    int m=(l+r)>>1;
    if(x==l&&y==r)
    {
        return root[t].mx;
    }
    int ans=-100000000;
    if(x<=m)
        ans=max(ans,query_mx(t*2,x,min(m,y)));
    if(y>m)
        ans=max(ans,query_mx(t*2+1,max(x,m+1),y));
    return ans;
}

int query_mi(int t,int x,int y)
{
    int l=root[t].l,r=root[t].r;
    int m=(l+r)>>1;
    if(x==l&&y==r)
    {
        return root[t].mi;
    }
    int ans=1000000000;
    if(x<=m)
        ans=min(ans,query_mi(t*2,x,min(m,y)));
    if(y>m)
        ans=min(ans,query_mi(t*2+1,max(x,m+1),y));
    return ans;
}

int main()
{
    while(~scanf("%d%d",&n,&k))
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(1,1,n);
        int tag=0;
        for(int i=k;i<=n;i++)
        {
            if(tag)
                printf(" ");
            printf("%d",query_mi(1,i-k+1,i));
            tag=1;
        }
        printf("\n");
        tag=0;
        for(int i=k;i<=n;i++)
        {
            if(tag)
                printf(" ");
            printf("%d",query_mx(1,i-k+1,i));
            tag=1;
        }
        printf("\n");
    }
    return 0;
}



然后是单调队列,应该是第一次写吧  用的deque   不过限于自己的水平   真心慢==

用deque来存数组下标

对于区间的最大值,我们可以用deque维护一个递减序列的数组下标。每次加入(t)操作,从队尾开始,把<=t的都踢掉,然后从队尾压入,这样队首代表的数字肯定是最大的,而且队首是下标最小的,这样每次查询就是取队首。


#include<stdio.h>
#include<string.h>
#include<deque>
#include<algorithm>
using namespace std;
#define N  1000010

int n,k,a[N],ami[N],amx[N],n1,n2;

deque<int>maxq;
deque<int>minq;

int main()
{
    while(~scanf("%d%d",&n,&k))
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }

        n1=n2=0;
        while(!maxq.empty()) maxq.pop_back();
        while(!minq.empty()) minq.pop_back();

        for(int i=1;i<=n;i++)
        {
            while(!maxq.empty()&&a[maxq.back()]<=a[i]) maxq.pop_back();
            maxq.push_back(i);
            while(!maxq.empty()&&(i-maxq.front()+1>k)) maxq.pop_front();
            if(i>=k)
            {
                amx[n1++]=a[maxq.front()];
            }
        }

        for(int i=1;i<=n;i++)
        {
            while(!minq.empty()&&a[minq.back()]>=a[i]) minq.pop_back();
            minq.push_back(i);
            while(!minq.empty()&&(i-minq.front()+1>k)) minq.pop_front();
            if(i>=k)
            {
                ami[n2++]=a[minq.front()];
            }
        }
        for(int i=0;i<n2;i++)
        {
            if(i!=0) printf(" ");
            printf("%d",ami[i]);
        }
        printf("\n");
        for(int i=0;i<n1;i++)
        {
            if(i!=0) printf(" ");
            printf("%d",amx[i]);
        }
        printf("\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值