zoukankan      html  css  js  c++  java
  • 单调队列

    bzoj1047 理想的正方形

    题目大意:求a*b的矩阵中一个n*n的子矩阵,使得子矩阵的最大值和最小值的差最小。

    思路:一开始认为能用二维线段树a掉,但lcomyn大神写了一下,结果T了,于是就寻找新的写法。借鉴了斜率优化的思路,发现单调队列可以优越的做到O(ab)的求出整个矩阵中每个点左面延伸n位的最值。我们用行上的单调队列维护出这个之后,再从列上单调队列一下,就能求出一个n*n子矩阵的最值了,然后比较一下,输出答案。注意这里单调队列中的是下标(这样写可能会有一些好处),所以写的时候要对应到数组中。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxnode 1010
    using namespace std;
    int q1[maxnode]={0},q2[maxnode]={0},map[maxnode][maxnode]={0},h1,h2,t1,t2,n,
        maxn[maxnode][maxnode]={0},minn[maxnode][maxnode]={0};
    void qmin(int i,int j)
    {
        while(h1<=t1&&q1[h1]<=j-n) ++h1;
        while(h1<=t1&&map[i][q1[t1]]>=map[i][j]) --t1;
        q1[++t1]=j;
    }
    void qmax(int i,int j)
    {
        while(h2<=t2&&q2[h2]<=j-n) ++h2;
        while(h2<=t2&&map[i][q2[t2]]<=map[i][j]) --t2;
        q2[++t2]=j;
    }
    void wmin(int i,int j)
    {
        while(h1<=t1&&q1[h1]<=i-n) ++h1;
        while(h1<=t1&&minn[q1[t1]][j]>=minn[i][j]) --t1;
        q1[++t1]=i;
    }
    void wmax(int i,int j)
    {
        while(h2<=t2&&q2[h2]<=i-n) ++h2;
        while(h2<=t2&&maxn[q2[t2]][j]<=maxn[i][j]) --t2;
        q2[++t2]=i;
    }
    int main()
    {
        int i,j,a,b,ans;
        scanf("%d%d%d",&a,&b,&n);
        for (i=1;i<=a;++i)
          for (j=1;j<=b;++j)
            scanf("%d",&map[i][j]);
        /*求点(i,j)左面n内的最大最小值*/
        for (i=1;i<=a;++i)
        {
          h1=h2=1;t1=t2=0;
          for (j=1;j<=b;++j)
          {
            qmin(i,j);qmax(i,j);
            if (j>=n)
            {
                minn[i][j]=map[i][q1[h1]];maxn[i][j]=map[i][q2[h2]];
            }
          }
        }
        /*求列j为右边界的矩形的ans*/
        ans=0x7fffffff;
        for (j=1;j<=b;++j)
        {
            h1=h2=1;t1=t2=0;
            for (i=1;i<=a;++i)
            {
                wmin(i,j);wmax(i,j);
                if (j>=n&&i>=n&&maxn[q2[h2]][j]-minn[q1[h1]][j]<ans) ans=maxn[q2[h2]][j]-minn[q1[h1]][j];
            }
        }
        printf("%d
    ",ans);
    }
    View Code

    xjoi T2

    题目大意:给定一个nm的矩阵,求最大最小值差不超过k的子矩阵的个数。

    思路:穷举i~j行,然后扫出每一列的最大最小值,用单调队列维护这些最大最小值,插入的时候就是从队尾比较着插入,但是查询的时候还要注意k的限制,所以先把队首那些不满足的弹出(但是要注意:如果这次没有弹出队首,符合的区间可能是上次更新时的位置,而不是0),然后累加答案。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxm 405
    #define LL long long
    using namespace std;
    int ai[maxm][maxm],q1[maxm],q2[maxm],maxn[maxm],minn[maxm];
    int main(){
        int n,m,k,i,j,a,b,h1,h2,t1,t2;LL ans=0;
        scanf("%d%d%d",&n,&m,&k);
        for (i=1;i<=n;++i)
          for (j=1;j<=m;++j) scanf("%d",&ai[i][j]);
        for (i=1;i<=n;++i){
          memset(maxn,0,sizeof(maxn));
          memset(minn,127,sizeof(minn));
          for (j=i;j<=n;++j){
              h1=h2=1;t1=t2=0;
            for (b=a=1;a<=m;++a){
                maxn[a]=max(maxn[a],ai[j][a]);
                while(h1<=t1&&maxn[a]>=maxn[q1[t1]]) --t1;
                minn[a]=min(minn[a],ai[j][a]);
                while(h2<=t2&&minn[a]<=minn[q2[t2]]) --t2;
                q1[++t1]=q2[++t2]=a;
                while(h1<=t1&&maxn[q1[h1]]-k>minn[a]){b=max(b,q1[h1]+1);++h1;}
                while(h2<=t2&&minn[q2[h2]]+k<maxn[a]){b=max(b,q2[h2]+1);++h2;}
                ans+=(LL)(a-b+1);
            }
          }
        }cout<<ans<<endl;
    }
    View Code
  • 相关阅读:
    Android之startActivity、startActivityForResult和setResult详解
    Android之Activity的标准写法参考
    Android之Handler用法总结[一]
    UHF天线知识汇编
    数字图像处理【一】基础理论
    S2SH之简易的Web Service实现
    Java Web开发环境搭建基础[Windows篇]
    Hadoop的安装(Ubuntu 12.10为例)
    【NOIP2016普及组复赛】魔法阵
    【NOIP2016提高A组集训第13场11.11】最大匹配
  • 原文地址:https://www.cnblogs.com/Rivendell/p/4621121.html
Copyright © 2011-2022 走看看