Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
A coloring is not really about the exact integers . It only cares which points are on the left of the vertical line and which points are below the horizontal line.
For a fixed vertical cut, ask: for which horizontal cuts do both the left side and the right side have at least one point below and at least one point above?
For any set of points , a horizontal cut splits into nonempty bottom/top parts iff
So for a fixed vertical cut with point sets and , valid horizontal thresholds satisfy
Now remember: different values can still give the same coloring if no point has a -coordinate crossed.
Sweep vertical cuts from left to right. Maintain on the left and right. For each distinct vertical coloring, add the number of distinct existing -coordinates in
Use a prefix array over present -coordinates to count that in .
The exact values of and are a red herring. Since all coordinates are integers, moving a cut inside an empty gap changes absolutely nothing. A vertical cut only determines the set
and a horizontal cut only determines
The color of a point is determined by membership in and . So two choices produce the same coloring iff they produce the same vertical prefix and the same horizontal prefix.
Thus, we should count pairs of distinct vertical/horizontal prefixes such that all four quadrants are nonempty.
Suppose the vertical cut is fixed. Let
A horizontal threshold is valid iff both and contain at least one point below/equal to and at least one point above .
For a set , this is equivalent to
So for both sides simultaneously, must satisfy
Define
Then valid horizontal cuts are those with
But we count distinct colorings, not integer values of . A horizontal prefix changes only when reaches an existing -coordinate. Therefore, for this fixed vertical cut, the number of distinct valid horizontal colorings is:
This can be answered in with a prefix array over present -coordinates.
Coordinates satisfy , so we can bucket points by and sweep .
During the sweep:
If the right side is still nonempty, compute
and add
if , where is the number of distinct present -coordinates at most .
No double counting happens: changing the vertical prefix changes at least one point from left-color to right-color or vice versa. Changing the horizontal prefix changes at least one point from bottom-color to top-color or vice versa. So every counted pair is a unique coloring.
Each point is moved once, and the min/max pointers only move monotonically. Therefore the sweep is linear.
per test case, and
over all test cases. Memory is . Fast, clean, no sorting tax. Nice.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<int> head(n + 2, -1), nxt(n), ys(n);
vector<int> freqY(n + 2, 0), pref(n + 1, 0);
for (int i = 0; i < n; i++) {
int x, y;
cin >> x >> y;
ys[i] = y;
nxt[i] = head[x];
head[x] = i;
freqY[y]++;
}
for (int y = 1; y <= n; y++) {
pref[y] = pref[y - 1] + (freqY[y] > 0);
}
int mnL = n + 1, mxL = 0;
int mnR = 1, mxR = n;
while (mnR <= n && freqY[mnR] == 0) mnR++;
while (mxR >= 1 && freqY[mxR] == 0) mxR--;
int cntL = 0;
ll ans = 0;
for (int x = 1; x <= n; x++) {
if (head[x] == -1) continue;
for (int id = head[x]; id != -1; id = nxt[id]) {
int y = ys[id];
cntL++;
mnL = min(mnL, y);
mxL = max(mxL, y);
freqY[y]--;
}
while (mnR <= n && freqY[mnR] == 0) mnR++;
while (mxR >= 1 && freqY[mxR] == 0) mxR--;
// This vertical prefix is usable only if there are points on both sides.
if (cntL < n) {
int lo = max(mnL, mnR);
int hi = min(mxL, mxR);
if (lo < hi) {
ans += pref[hi - 1] - pref[lo - 1];
}
}
}
cout << ans << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<int> head(n + 2, -1), nxt(n), ys(n);
vector<int> freqY(n + 2, 0), pref(n + 1, 0);
for (int i = 0; i < n; i++) {
int x, y;
cin >> x >> y;
ys[i] = y;
nxt[i] = head[x];
head[x] = i;
freqY[y]++;
}
for (int y = 1; y <= n; y++) {
pref[y] = pref[y - 1] + (freqY[y] > 0);
}
int mnL = n + 1, mxL = 0;
int mnR = 1, mxR = n;
while (mnR <= n && freqY[mnR] == 0) mnR++;
while (mxR >= 1 && freqY[mxR] == 0) mxR--;
int cntL = 0;
ll ans = 0;
for (int x = 1; x <= n; x++) {
if (head[x] == -1) continue;
for (int id = head[x]; id != -1; id = nxt[id]) {
int y = ys[id];
cntL++;
mnL = min(mnL, y);
mxL = max(mxL, y);
freqY[y]--;
}
while (mnR <= n && freqY[mnR] == 0) mnR++;
while (mxR >= 1 && freqY[mxR] == 0) mxR--;
// This vertical prefix is usable only if there are points on both sides.
if (cntL < n) {
int lo = max(mnL, mnR);
int hi = min(mxL, mxR);
if (lo < hi) {
ans += pref[hi - 1] - pref[lo - 1];
}
}
}
cout << ans << '\n';
}
return 0;
}