介绍

一维差分可以用于解决以下问题:

给定一系列的区间加/减操作,最后询问整个数组的元素。

那么二维差分就可以解决:

给定一系列的矩阵加/减操作,最后询问整个矩阵中的元素。

二维差分原理

我们知道,二维前缀和的计算方式是:

$$sum[x][y] = sum[x-1][y] + sum[x][y-1] - sum[x-1][y-1]$$

所以我们思考,对于差分数组 $d[x][y]$,如果我们要给一个矩阵

$$[x_1,y_1][x_2,y_2]$$

全部加 $1$,即左上角为 $(x_1,y_1)$,右下角为 $(x_2,y_2)$ 的矩阵全部加 $1$,应该怎么处理?

img

注意到如果我们进行二维前缀和的话,修改一个差分数组 $d[x][y]$ 影响到的是 $(x,y)$ 右下方的所有元素的值。

我们想要的是 紫色部分 全部加 $1$。

那么如果我们让 $d[x_1][y_1]$ 加 $1$,那么影响到的是所有的 紫色加红色 部分。

于是,我们可以通过让 $d[x_1][y_2+1]$ 和 $d[x_2+1][y_1]$ 全部减去 $1$ 来消除红色部分

然而 绿色部分 被减去了两次,所以我们再给 $d[x_2+1][y_2+1]$ 加上 $1$。

在所有的操作结束后,使用 二维前缀和 的方式来获得矩阵值即可。

void update(ll arr[][maxn], int xl, int xr, int yl, int yr, ll val) {
    arr[xl][yl] += val;
    arr[xr+1][yr+1] += val;
    arr[xl][yr+1] -= val;
    arr[xr+1][yl] -= val;
}

例题

例1 2018ICPC焦作J题 Carpets Removal

题意

给定 $m\times m$ 的一个矩阵,并且给定 $n$ 个地毯(每个地毯是一个矩形)。

我们需要移除 恰好两个地毯,使得 没有被地毯覆盖到的格子数量 最大。

输出这个最大值。

其中,$3 \leq n \leq 3 \times 10^5, 1 \leq m \leq 1500$。

题解

首先,我们可以利用二维差分,求出每个格子的覆盖次数。

我们知道,如果一个格子被覆盖的次数 $\geq 3$,那么可以直接忽略。

所以我们只考虑覆盖次数为 $1$ 或者 $2$ 的格子。

我们分开讨论。


对于覆盖次数为 $1$ 的格子,我们可以把它们单独拿出来,在一个全部为 $0$ 的矩阵中,然后把这些 $1$ 放进去。

这样我们可以得出每个地毯所覆盖的 $1$ 的数量。

我们设第 $i$ 个地毯覆盖的 $1$ 的数量为 $a_i$。


对于覆盖次数为 $2$ 的格子,假设覆盖它的地毯分别为 $i,j$,那么我们设 $b_{ij}$ 为地毯 $i,j$ 共同覆盖的,覆盖次数为 $2$ 的格子数量。

所以最后的最大值就是

$$\max\limits_{(i,j)}\{a_i+a_j+b_{ij}\}$$


$a_i$ 我们可以求出,但是 $b_{ij}$ 呢?

假设我们知道对于每个覆盖次数为 $2$ 的格子,覆盖它的两个地毯 index 为 $i,j$,那么这个 $b_{ij}$ 就可以求出。

我们利用 二维差分 来记录这样的信息!

除了我们维护的 cnt[][] 来代表覆盖次数以外,我们再额外维护两个信息:

  1. sum[][]:如果 $(i,j)$ 被地毯 $x$ 覆盖,那么它的值会被加上 $x$。
  2. sum2[][]:如果 $(i,j)$ 被地毯 $x$ 覆盖,那么它的值会被加上 $x^2$。

对于 cnt[i][j] == 1 的格子,我们只要看一下 sum[i][j],就可以知道它是被哪个地毯覆盖的了。

对于 cnt[i][j] == 2 的格子,我们可以知道它被两个地毯 $x,y$ 所覆盖,并且我们知道 $(x+y)$ 与 $(x^2+y^2)$ 的值。

那么我们只要利用 $$2(x^2+y^2) - (x+y)^2 = x^2 + y^2 - 2xy = (x-y)^2$$

就可以求出 $|x-y|$ 的值,那么用 $\frac{(x+y) \pm |x-y|}{2}$ 即可求出 $x,y$。


最后要注意,有可能有 $b_{ij} = 0$,所以我们还需要让答案再考虑一下

$$\max\limits_{(i,j)}\{a_i+a_j\}$$

这个只要在 $a_i$ 中找到前 $2$ 大的加起来就可以了。

代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1515;
const int maxm = 3e5+50;

ll n,m;
ll cnt[maxn][maxn];
ll sum1[maxn][maxn], sum2[maxn][maxn];
void update(ll arr[][maxn], int xl, int xr, int yl, int yr, ll val) {
    arr[xl][yl] += val;
    arr[xr+1][yr+1] += val;
    arr[xl][yr+1] -= val;
    arr[xr+1][yl] -= val;
}

ll one[maxm];
void solve() {
    cin >> n >> m;
    for (ll i = 1; i <= n; i++) {
        int xl,xr,yl,yr; cin >> xl >> xr >> yl >> yr;
        update(cnt, xl, xr, yl, yr, 1);
        update(sum1, xl, xr, yl, yr, i);
        update(sum2, xl, xr, yl, yr, i*i);
    }
    map<pii,int> mp;
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= m; j++) {
            cnt[i][j] += cnt[i][j-1] + cnt[i-1][j] - cnt[i-1][j-1];
            sum1[i][j] += sum1[i][j-1] + sum1[i-1][j] - sum1[i-1][j-1];
            sum2[i][j] += sum2[i][j-1] + sum2[i-1][j] - sum2[i-1][j-1];

            if (cnt[i][j] == 1) {
                ll x = sum1[i][j];
                one[x]++;
            } else if (cnt[i][j] == 2) {
                ll d = sqrt(2LL * sum2[i][j] - sum1[i][j] * sum1[i][j]);  // d = abs(x-y)
                ll x = (sum1[i][j] + d) / 2, y = (sum1[i][j] - d) / 2;
                if (x > y) swap(x, y);
                mp[{x,y}]++;
            }
        }
    }
    ll ans = 0;
    for (auto p : mp) {
        int x = p.first.first, y = p.first.second;
        ll a = p.second;
        ans = max(ans, one[x] + one[y] + a);
    }
    ll m1 = 0, m2 = 0;
    for (int i = 1; i <= n; i++) {
        m1 = max(m1, one[i]);
        if (m1 > m2) {
            swap(m1, m2);
        }
    }
    ans = max(ans, m1 + m2);
    ans = -ans;
    LOG(ans);
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= m; j++) {
            ans += (cnt[i][j] > 0);
        }
    }
    cout << ans << "\n";

    for (int i = 0; i <= m+2; i++) {
        for (int j = 0; j <= m+2; j++) {
            cnt[i][j] = sum1[i][j] = sum2[i][j] = 0;
        }
    }
    fill(one, one+n+2, 0);
}

int main() {
    int T; cin >> T;
    while (T--) {
        solve();
    }
}

参考链接

  1. https://www.cnblogs.com/LMCC1108/p/10753451.html