• [日常摸鱼]滑动窗口(单调队列大法好)


    期中考挂完又来划水啦…

    然后在洛谷上随机抽了一题

    Luogu1886滑动窗口

    然后发现好像以前在哪里见过这个(后来发现是rxz的blog

    一开始是想到写st表,然后蜜汁三个点爆了内存QAQ…

    后来想起了这道题…就去翻了下那篇blog,学了下单调队列…

    然后我的做法应该挺大众的

    就以维护最小值为例,在队列里记录队列里每个元素进队的位置(时间)

    每次直接把要弹出去的队首元素弹出去,然后对于要新加入的元素$a[i]$跟队尾元素比较,如果比他大就直接弹出去(因为我们要的是最小值所以比他大的话就没有用了)

    一直弹到不能弹,然后在把$a[i]$加到队尾,最大值也同理

    因为在每次维护最值的时候每个元素最多只会进出队列一次,所以复杂度就是$O(n)$了

    我写的好像有点长…

    OwO
    #include<cstdio>
    #include<deque>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N=1000005;
    
    inline int read()
    {
        int s=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){s=s*10+c-'0';c=getchar();}
        return s*f;
    }
    
    int n,k;
    
    int a[N];
    
    struct point
    {
        int tim,val;
        point(int t,int v):tim(t),val(v){}
    };
    
    deque<point>q;
    
    inline void solve1()
    {
        for(register int i=1;i<=k;i++)
        {
            while(!q.empty()&&q.back().val>a[i])q.pop_back();
            q.push_back(point(i,a[i]));
        }
        
        printf("%d ",q.front().val); 
        
        for(register int i=k+1;i<=n;i++)
        {
            while(!q.empty()&&q.front().tim+k-1<i)q.pop_front();
            
            while(!q.empty()&&q.back().val>a[i])q.pop_back();
            q.push_back(point(i,a[i]));
            
            printf("%d ",q.front().val);
        }
        
        printf("\n");
    }
    
    inline void solve2()
    {
        while(!q.empty())q.pop_back();
        
        for(register int i=1;i<=k;i++)
        {
            while(!q.empty()&&q.back().val<a[i])q.pop_back();
            q.push_back(point(i,a[i]));
        }
        
        printf("%d ",q.front().val); 
        
        for(register int i=k+1;i<=n;i++)
        {
            while(!q.empty()&&q.front().tim+k-1<i)q.pop_front();
            
            while(!q.empty()&&q.back().val<a[i])q.pop_back();
            q.push_back(point(i,a[i]));
            
            printf("%d ",q.front().val);
        }
    }
    
    int main()
    {
        n=read();k=read();
        
        for(register int i=1;i<=n;i++)a[i]=read();
        
        solve1();
        
        solve2();
        
        return 0;
    }

    st表:

    OwO
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N=1000005;
    
    const int INF=(~0u>>1);
    
    inline int read()
    {
        int s=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){s=s*10+c-'0';c=getchar();}
        return s*f;
    }
    
    int n,k;
    
    int Log[N],f_min[N][23],f_max[N][23];
    
    inline int query_min(int l,int r)
    {
        int m=Log[r-l+1];
        return min(f_min[l][m],f_min[r-(1<<m)+1][m]);
    }
    
    inline int query_max(int l,int r)
    {
        int m=Log[r-l+1];
        return max(f_max[l][m],f_max[r-(1<<m)+1][m]);
    }
    
    int main()
    {    
        n=read();k=read();
        
        Log[0]=-1;
        
        for(register int i=1;i<=n;i++)Log[i]=Log[(i>>1)]+1;
        
        for(register int i=1;i<=n;i++)
            for(register int j=0;j<23;j++)f_min[i][j]=INF;
        
        for(register int i=1;i<=n;i++)f_min[i][0]=f_max[i][0]=read();
        
        for(register int j=1;j<23;j++)
            for(register int i=1;i+(1<<(j-1))-1<=n;i++)
            {
                f_min[i][j]=min(f_min[i][j-1],f_min[i+(1<<(j-1))][j-1]);
                f_max[i][j]=max(f_max[i][j-1],f_max[i+(1<<(j-1))][j-1]); 
            }
            
        
        
        for(register int i=1;i+k-1<=n;i++)printf("%d ",query_min(i,i+k-1));
        
        printf("\n");
        
        for(register int i=1;i+k-1<=n;i++)printf("%d ",query_max(i,i+k-1)); 
        return 0;
    }

    还试了下线段树…T掉一个点Orz

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N=1000005;
    
    const int INF=(~0u>>1);
    
    inline int read()
    {
        int s=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){s=s*10+c-'0';c=getchar();}
        return s*f;
    }
    
    int n,k;
    
    int t1[N<<2],t2[N<<2],a[N];
    
    #define lson (node<<1)
    #define rson (node<<1|1)
    
    inline void push_up(int node)
    {
        t1[node]=max(t1[lson],t1[rson]);
        t2[node]=min(t2[lson],t2[rson]);
    }
    
    inline void build(int node,int l,int r)
    {
        if(l==r)
        {
            t1[node]=t2[node]=a[l];
            return;
        }
        
        int mid=(l+r)>>1;
        
        build(lson,l,mid);build(rson,mid+1,r);
        
        push_up(node);
    }
    
    inline int query_max(int node,int l,int r,int ql,int qr)
    {
        if(ql<=l&&r<=qr)return t1[node];
        
        int mid=(l+r)>>1;
        int res=-INF;
        
        if(mid>=ql)res=max(res,query_max(lson,l,mid,ql,qr));
        if(mid+1<=qr)res=max(res,query_max(rson,mid+1,r,ql,qr));
        
        return res; 
    }
    
    inline int query_min(int node,int l,int r,int ql,int qr)
    {
        if(ql<=l&&r<=qr)return t2[node];
        
        int mid=(l+r)>>1;
        int res=INF;
        
        if(mid>=ql)res=min(res,query_min(lson,l,mid,ql,qr));
        if(mid+1<=qr)res=min(res,query_min(rson,mid+1,r,ql,qr));
        
        return res;
    }
    #undef lson
    #undef rson
    
    int main()
    {
        n=read();k=read();
        
        for(register int i=1;i<=n;i++)a[i]=read();
        
        build(1,1,n);
        
        for(register int i=1;i+k-1<=n;i++)printf("%d ",query_min(1,1,n,i,i+k-1));
        
        printf("\n");
        
        for(register int i=1;i+k-1<=n;i++)printf("%d ",query_max(1,1,n,i,i+k-1));
        
        return 0; 
    }
    OwO
  • 相关阅读:
    poj_1084 剪枝-IDA*
    搜索算法
    poj_1475 BFS+BFS
    chrome浏览器经常无响应
    charles抓包工具的使用:手机抓包设置和安装证书
    charles抓包工具的使用:概述
    不同局域网如何利用charles对app进行抓包
    fiddler之使用教程(一)
    一点感触
    单元测试框架处理多组数据的另一种写法:基于构造函数和超继承
  • 原文地址:https://www.cnblogs.com/yoshinow2001/p/7856581.html
Copyright © 2020-2023  润新知