• 二维区间的一些sao做法


    1. 与数据结构相关

    最典型的就是树套树了,这里的例题是二维线段树.

    牛客2020 CCPC Wannafly Winter Camp Day5 Div.1&2 I Practice for KD Tree

    找二维区间最大值

    这里需要注意的是,一开始题目要进行区间加的操作,所以我们要用到二维前缀和的思想

    可以这么记住:上行、右列先拓展,左下右上+,左上右下-。

    #include <bits/stdc++.h>
    #define mp make_pair
    using namespace std;
    typedef long long ll;
    inline ll read(){ll s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return s*w;}
    const int maxn = 2e3+10;
    const int INF = 0x3f3f3f3f; 
    int n,m1,m2,i,j;
    ll maxx[maxn<<2][maxn<<2],a[maxn][maxn],v;
    void add(int x1,int y1,int x2,int y2,ll value)
    {
        a[x1][y1]+=v;
        a[x2+1][y2+1]+=v;
        a[x2+1][y1]-=v;
        a[x1][y2+1]-=v;
    }
    void updatey(int l,int r,int num,int x,int y,ll value)
    {
        maxx[x][num]=max(maxx[x][num],value);
        if (l==r) return;
        int mid=(l+r)>>1;
        if (y<=mid) updatey(l,mid,num*2,x,y,value);
            else updatey(mid+1,r,num*2+1,x,y,value);
    }
    void updatex(int l,int r,int num,int x,int y,ll value)
    {
        updatey(1,n,1,num,y,value);
        if (l==r) return;
        int mid=(l+r)>>1;
        if (x<=mid) updatex(l,mid,num*2,x,y,value);
            else updatex(mid+1,r,num*2+1,x,y,value);
    }
    ll queryy(int l,int r,int num,int limitt_y1,int limitt_y2,int xroot)
    {
        if (limitt_y1<=l && r<=limitt_y2)
        {
            return maxx[xroot][num];
        }
        ll ans=0;
        int mid=(l+r)>>1;
        if (limitt_y1<=mid) ans=max(ans,queryy(l,mid,num*2,limitt_y1,limitt_y2,xroot));
        if (limitt_y2>mid) ans=max(ans,queryy(mid+1,r,num*2+1,limitt_y1,limitt_y2,xroot));
        return ans;
    }
    ll queryx(int l,int r,int num,int limitt_x1,int limitt_x2,int limitt_y1,int limitt_y2)
    {
        if (limitt_x1<=l && r<=limitt_x2)
        {
            return queryy(1,n,1,limitt_y1,limitt_y2,num);
        }
        ll ans=0;
        int mid=(l+r)>>1;
        if (limitt_x1<=mid) ans=max(ans,queryx(l,mid,num*2,limitt_x1,limitt_x2,limitt_y1,limitt_y2));
        if (limitt_x2>mid) ans=max(ans,queryx(mid+1,r,num*2+1,limitt_x1,limitt_x2,limitt_y1,limitt_y2));
        return ans;
    }
    int main()
    {
        n=read();
        m1=read();    
        m2=read();
        int x1,y1,x2,y2;
        for (i=1;i<=m1;i++)
        {
            scanf("%d%d%d%d%lld",&x1,&y1,&x2,&y2,&v);
            add(x1,y1,x2,y2,v);
        }
        for (i=1;i<=n;i++)
            for (j=1;j<=n;j++)
                a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
        for (i=1;i<=n;i++)
            for (j=1;j<=n;j++)
                updatex(1,n,1,i,j,a[i][j]);
        while (m2--)
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            printf("%lld
    ",queryx(1,n,1,x1,x2,y1,y2));
        }
        return 0;
    } 
    View Code

    牛客的评测不知道是什么原因,如果把x1,y1,x2,y2设在代码最开头那里的话,就会CE,而把它们放在主函数里面就不会......

    2. 与算法相关

    记忆化dp

    codeforces 1199F

    题意就是要把整个矩阵涂白,然后求最小代价。

    我们设dp[x1][y1][x2][y2],(x1,y1)为左下坐标,(x2,y2)为右上坐标,表示这个矩阵涂白的最小代价

    可以用拼接的方法来进行转移,对于当前矩阵,我们可以通过拼接上下两个长相等的矩阵得到,也可以拼接左右两个宽相等的矩阵得到。

    #include <bits/stdc++.h>
    #define mp make_pair
    using namespace std;
    typedef long long ll;
    inline int read(){int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return s*w;}
    const int maxn = 55;
    const int INF = 0x3f3f3f3f; 
    int n,i,f[maxn][maxn][maxn][maxn];
    char s[maxn][maxn];
    int solve(int x1,int y1,int x2,int y2)
    {
        if (f[x1][y1][x2][y2]!=-1) return f[x1][y1][x2][y2];
        if (x1==x2 && y1==y2)
        {
            if (s[x1][y1]=='#') f[x1][y1][x2][y2]=1;
                else f[x1][y1][x2][y2]=0;
            return f[x1][y1][x2][y2];
        }
        f[x1][y1][x2][y2]=max(x2-x1+1,y2-y1+1);
        for (int i=x1;i<x2;i++)
        {
            if (f[x1][y1][i][y2]==-1) solve(x1,y1,i,y2);
            if (f[i+1][y1][x2][y2]==-1) solve(i+1,y1,x2,y2);
            f[x1][y1][x2][y2]=min(f[x1][y1][x2][y2],f[x1][y1][i][y2]+f[i+1][y1][x2][y2]);
        }
        for (int i=y1;i<y2;i++)
        {
            if (f[x1][i+1][x2][y2]==-1) solve(x1,i+1,x2,y2);
            if (f[x1][y1][x2][i]==-1) solve(x1,y1,x2,i);
            f[x1][y1][x2][y2]=min(f[x1][y1][x2][y2],f[x1][i+1][x2][y2]+f[x1][y1][x2][i]);
        }    
        return f[x1][y1][x2][y2];
    }
    int main()
    {
        n=read();
        for (i=1;i<=n;i++)
        {
            scanf("%s",s[i]+1);
        }
        memset(f,-1,sizeof(f));
        cout<<solve(1,1,n,n);
        return 0;
     } 
    View Code

    二维RMQ

    就是上面那题二维线段树变成RMQ的做法(过肯定是过不了的,内存肯定会爆,知道做法就行)

    #include <bits/stdc++.h>
    #define mp make_pair
    using namespace std;
    typedef long long ll;
    inline ll read(){ll s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return s*w;}
    const int maxn = 2e3+1;
    const int INF = 0x3f3f3f3f; 
    int n,m1,m2,i,j;
    ll maxx[maxn][maxn][11][11],a[maxn][maxn],v;
    void add(int x1,int y1,int x2,int y2,ll value)
    {
        a[x1][y1]+=v;
        a[x2+1][y2+1]+=v;
        a[x2+1][y1]-=v;
        a[x1][y2+1]-=v;
    }
    void init()
    {
        int i,j,k,p;
        for (i=1;i<=n;i++)
            for (j=1;j<=n;j++)
                maxx[i][j][0][0]=a[i][j];
    //    pre[2]=pre[3]=1;
    //    for (i=4;i<=n;i++) pre[i]=pre[i>>1]+1;
    //    int up1,up2=pre[n]+1;
        int up1=(int)log2(n);
        int up2=(int)log2(n);
        for (i=0;i<=up1;i++)
        for (j=0;j<=up2;j++)
        {
        //    cout<<1<<endl;
            if (!i && !j) continue;
            for (k=1;(k+(1<<i)-1)<=n;k++)
            for (p=1;(p+(1<<j)-1)<=n;p++)
            {
                if (i==0) maxx[k][p][i][j]=max(maxx[k][p][i][j-1],maxx[k][p+(1<<(j-1))][i][j-1]);
                    else maxx[k][p][i][j]=max(maxx[k][p][i-1][j],maxx[k+(1<<(i-1))][p][i-1][j]);
            }
        }
    }
    ll query(int x1,int y1,int x2,int y2)
    {
        ll ans=-INF;
        int p=(int)log2((x2-x1+1));
        int q=(int)log2((y2-y1+1));
        ans=max(maxx[x1][y1][p][q],maxx[x1][y2-(1<<q)+1][p][q]);
        ans=max(ans,max(maxx[x2-(1<<p)+1][y1][p][q],maxx[x2-(1<<p)+1][y2-(1<<q)+1][p][q]));
        return ans;
    }
    int main()
    {
        n=read();
        m1=read();    
        m2=read();
        int x1,y1,x2,y2;
        for (i=1;i<=m1;i++)
        {
            scanf("%d%d%d%d%lld",&x1,&y1,&x2,&y2,&v);
            add(x1,y1,x2,y2,v);
        }
        for (i=1;i<=n;i++)
            for (j=1;j<=n;j++)
                a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
        init();
        while (m2--)
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            printf("%lld
    ",query(x1,y1,x2,y2));
        }
        return 0;
    } 
    View Code
  • 相关阅读:
    随便说说
    郁闷
    请各栏目的负责人,开始整理自己栏目的文章
    祝博客园生日快乐
    Windows Live Writer中打开博客日志(最新版可以支持打开3000以内的日志)
    编译器优化对齐(字节对齐)
    HDlock 锁住硬盘的解决方式
    linux中env,export, set的区别
    System Volume Information 文件夹权限控制
    BOOL与bool的区别(bool不是c的关键字,c++中bool也不是int)
  • 原文地址:https://www.cnblogs.com/Y-Knightqin/p/12549530.html
Copyright © 2020-2023  润新知