049.二维差分

一维差分

对于原始数组a[]

通过d[i]=a[i]-a[i-1]初始化出d[]差分数组

对差分数组进行若干次修改

// 在[l,r]上加k
void change(int l,int r,int k){
    d[l]+=k;
    d[r+1]-=k;
}

最后update得到最终的a[]

void update(int n){
    for(int i=1;i<=n;++i){
        d[i]+=d[i-1];
        a[i]=d[i];
    }
}

或者直接在原始数组上操作a[i]-=a[i-1]进行初始化

void change(int l,int r,int k){
    a[l]+=k;
    a[r+1]-=k;
}
void update(int n){
    for(int i=1;i<=n;++i){
        a[i]+=a[i-1];
    }
}

二维差分

为了避免若干边界问题

对于一个n * m的原始数组a[][]

我们加工出一个(n+2)*(m+2)的差分数组d[][]

最外层都用0包裹

//在以[i,j]为左上角,[x,y]为右下角的矩形 + k
void change(int i,int j,int x,int y,int k){
    d[i][j]+=k;
    d[i][y+1]-=k;
    d[x+1][j]-=k;
    d[x+1][y+1]+=k;
}

update操作类似二维前缀和

void update(int n,int m){
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            d[i][j]=d[i-1][j]+d[i][j-1]-d[i-1][j-1];
        }
    }
}

习题

贴邮票

尝试将每一个0都作为左上角进行贴邮票

能贴则贴(邮票对应区域和为0)

不修改原始数组,在差分数组上进行贴邮票行为

最后检查是否原数组的每一个0在差分数组上都被覆盖

leetcode 2132

class Solution {
    void change(int i,int j,int x,int y,int k,vector<vector<int>>&d){
        d[i][j]+=k;
        d[i][y+1]-=k;
        d[x+1][j]-=k;
        d[x+1][y+1]+=k;
    }
    void update(vector<vector<int>>&d,int n,int m){
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                d[i][j]+=d[i-1][j]+d[i][j-1]-d[i-1][j-1];
            }
        }
    }
public:
    bool possibleToStamp(vector<vector<int>>& M, int h, int w) {
        int n=M.size();
        int m=M[0].size();
        vector<vector<int>>p(n+1,vector<int>(m+1));
        vector<vector<int>>d(n+2,vector<int>(m+2));
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j){
                p[i+1][j+1]=p[i+1][j]+p[i][j+1]+M[i][j]-p[i][j];
            }
        }
        for(int i=0;i+h<=n;++i){
            for(int j=0;j+w<=m;++j){
                int x=i+h;
                int y=j+w;
                int sum=p[x][y]+p[i][j]-p[i][y]-p[x][j];
                if(sum==0){
                    change(i+1,j+1,x,y,1,d);
                }
            }
        }
        update(d,n,m);
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                if(M[i-1][j-1]==0&&d[i][j]==0)return 0;
            }
        }
        return 1;
    }
};

最大祝福场

离散化 + 二维差分

先对原坐标轴进行放大,规避小数

然后是离散化(排序,去重,二分

update的同时更新ans

leetcode 74

class Solution {
public:
    int fieldOfGreatestBlessing(vector<vector<int>>& f) {
        vector<long>X,Y;
        for(auto a:f){
            long x=(long)a[0]*2,y=(long)a[1]*2,r=a[2];
            X.push_back(x-r);
            X.push_back(x+r);
            Y.push_back(y-r);
            Y.push_back(y+r);
        }
        ranges::sort(X);
        X.erase(unique(X.begin(),X.end()),X.end());
        ranges::sort(Y);        
        Y.erase(unique(Y.begin(),Y.end()),Y.end());
        int n=X.size();
        int m=Y.size();
        vector<vector<int>>d(n+2,vector<int>(m+2));
        for(auto a:f){
            long xx=(long)a[0]*2,yy=(long)a[1]*2,r=a[2];
            long x1=xx-r;
            long y1=yy-r;
            long x2=xx+r;
            long y2=yy+r;
            int i=lower_bound(X.begin(),X.end(),x1)-X.begin()+1;
            int x=lower_bound(X.begin(),X.end(),x2)-X.begin()+1;
            int j=lower_bound(Y.begin(),Y.end(),y1)-Y.begin()+1;
            int y=lower_bound(Y.begin(),Y.end(),y2)-Y.begin()+1;
            d[i][j]++;
            d[i][y+1]--;
            d[x+1][j]--;
            d[x+1][y+1]++;
        }
        int ans=0;
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                d[i][j]+=d[i-1][j]+d[i][j-1]-d[i-1][j-1];
                ans=max(ans,d[i][j]);
            }
        }
        return ans;
    }
};
posted @ 2026-01-18 10:57  射杀百头  阅读(2)  评论(0)    收藏  举报