Gym102028J
题意
给 \(m\ \times\ m\) 的网格,上面有 \(n\) 个长方形。
多测,问删去两个,剩下长方形覆盖面积的最小值。
\(3\ \leq\ n\ \leq\ 3\times 10^5,\ 1\ \leq\ m\ \leq\ 1500,\ \sum n\ \leq\ 2\times 10^6,\ \sum m^2\ \leq\ 5\times 10^7\)。
做法1
对每个长方形求出只删这一个长方形减小的面积,再对网格中的被恰好两个长方形覆盖的每个小格子求出覆盖这个格子的两个长方形是什么就行了。
后者可以用扫描线+线段树维护。
时间复杂度 \(O(n\log m\ +\ m^2)\)。
做法2
与求覆盖每个网格中小格长方形个数相似,采用二维差分的想法,如果对于被恰好覆盖两次的小格能知道覆盖这个小格的长方形编号和以及编号的平方和即可。故对每个小格 \((x,\ y)\) 维护三个值 \(f[x][y][0/1/2]\),对于每个长方形做如下操作即可:
++xr;
++yr;
++f[xl][yl][0];
++f[xr][yr][0];
--f[xl][yr][0];
--f[xr][yl][0];
f[xl][yl][1] += i;
f[xr][yr][1] += i;
f[xl][yr][1] -= i;
f[xr][yl][1] -= i;
long long j = (long long) i * i;
f[xl][yl][2] += j;
f[xr][yr][2] += j;
f[xl][yr][2] -= j;
f[xr][yl][2] -= j;
再对每个 \(f[x][y][0]\ =\ 2\) 的解个方程即可。
时间复杂度 \(O(n\ +\ m^2)\)。
代码
#include <bits/stdc++.h>
#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif
using namespace std;
template<int input_SZ, int output_SZ> struct IO {
char s[input_SZ], t[output_SZ], *a, *b;
IO() { fread(s, 1, input_SZ, stdin); a = s; b = t; }
~IO() { fwrite(t, 1, b - t, stdout); }
char nextchar() {
for(;;) {
if(*a >= 'A' && *a <= 'Z' || *a == '!' || *a == '?') return *a++;
a++;
}
}
int nextint() {
while(*a != '-' && (*a < '0' || *a > '9')) ++a;
bool flag = 0; int x = 0;
if(*a == '-') ++a, flag = 1;
while(*a >= '0' && *a <= '9') x = x * 10 + *a++ - '0';
if(flag) x = -x;
return x;
}
long long nextll() {
while(*a != '-' && (*a < '0' || *a > '9')) ++a;
bool flag = 0; long long x = 0;
if(*a == '-') ++a, flag = 1;
while(*a >= '0' && *a <= '9') x = x * 10 + *a++ - '0';
if(flag) x = -x;
return x;
}
void outchar(char c) {
*b++ = c;
if(b - t > output_SZ - 25) { fwrite(t, 1, b - t, stdout); b = t; }
return;
}
template<typename T> void outnum(T x) {
if(!x) { *b++ = '0'; return; }
if(x < 0) *b++ = '-', x = -x;
static char s[20], *a;
a = s;
while(x) {
T y = x / 10;
*a++ = x - y * 10 + '0';
x = y;
}
while(a != s) *b++ = *--a;
if(b - t > output_SZ - 25) { fwrite(t, 1, b - t, stdout); b = t; }
return;
}
template<typename T> void outnum(T x, char c) {
return outnum(x), outchar(c);
}
};
IO<(1 << 26) | 10, (1 << 20) | 10> io;
int main() {
ios::sync_with_stdio(false);
auto solve = [&]() {
int n = io.nextint(), m = io.nextint();
static const int maxn = 3e5 + 10, maxm = 1510;
static long long f[maxm][maxm][3];
static int s[maxn];
static vector<int> g[maxn];
for (int i = 0; i <= m; ++i) for (int j = 0; j <= m; ++j) memset(f[i][j], 0, sizeof f[i][j]);
for (int i = 1; i <= n; ++i) {
int xl, xr, yl, yr;
xl = io.nextint();
xr = io.nextint();
yl = io.nextint();
yr = io.nextint();
g[i].clear();
s[i] = 0;
++xr;
++yr;
++f[xl][yl][0];
++f[xr][yr][0];
--f[xl][yr][0];
--f[xr][yl][0];
f[xl][yl][1] += i;
f[xr][yr][1] += i;
f[xl][yr][1] -= i;
f[xr][yl][1] -= i;
long long j = (long long) i * i;
f[xl][yl][2] += j;
f[xr][yr][2] += j;
f[xl][yr][2] -= j;
f[xr][yl][2] -= j;
}
int tots = 0, maxs = 0;
for (int i = 1; i <= m; ++i) for (int j = 1; j <= m; ++j) {
for (int k = 0; k < 3; ++k) f[i][j][k] += f[i - 1][j][k] - f[i - 1][j - 1][k] + f[i][j - 1][k];
if(f[i][j][0]) tots++;
if(f[i][j][0] == 1) ++s[f[i][j][1]];
else if(f[i][j][0] == 2) {
long long a = f[i][j][1], b = f[i][j][2], d = sqrtl(4ll * a * a - 8ll * (a * a - b));
int x = (2ll * a + d) / 4ll, y = (2ll * a - d) / 4ll;
g[x].push_back(y);
g[y].push_back(x);
}
}
for (int u = 1; u <= n; ++u) {
static int pool[maxn];
for (int v: g[u]) pool[v] = 0;
for (int v: g[u]) ++pool[v];
for (int v: g[u]) maxs = max(maxs, s[u] + s[v] + pool[v]);
}
sort(s + 1, s + n + 1);
maxs = max(maxs, s[n - 1] + s[n]);
cout << tots - maxs << endl;
return;
};
int T;
T = io.nextint();
while(T--) solve();
return 0;
}