Description
定义一个点集是“好的”,那么其中任意两点之间满足下列三个条件之一:
- 横坐标相同
- 纵坐标相同
- 以这两个点为顶点的长方形包含(在内部或边缘)其他的至少一个点。
现在有 (n) 个点,找到一种添加点的方案,使得这个集合是“好的”。
构造其中一组总点数不超过 (2 imes 10^5) 的可行解。
Hint
- (1le nle 10^4)
- (| ext{坐标大小}| le 10^9)
Solution
平面分治。
假如将点按 (x) 坐标排序,取中间点的 (x) 坐标作为中间线的 (x) 坐标,然后对所有点做这个中间线上的 投影,所形成的点就是要添加的点。加入这些点之后,可以发现中间线异侧的点对全都满足条件。
那同侧的呢?使用 踢皮球大法 递归处理。于是做好了。如果要判断重复点的话只要用一个 set
就好了。
Code
/*
* Author : _Wallace_
* Source : https://www.cnblogs.com/-Wallace-/
* Problem : Codeforces 97B Superset
*/
#include <algorithm>
#include <iostream>
#include <set>
using namespace std;
const int N = 2e5 + 5;
struct Point {
int x, y;
inline Point() { }
inline Point(int _x, int _y) : x(_x), y(_y) { }
inline bool operator < (const Point& t) const {
return x != t.x ? x < t.x : y < t.y;
}
} p[N];
set<Point> points;
int n;
void solve(int l, int r) {
if (l == r) return;
int mid = (l + r) >> 1, x = p[mid].x;
solve(l, mid), solve(mid + 1, r);
for (register int i = l; i <= r; i++)
points.insert(Point(x, p[i].y));
}
signed main() {
ios::sync_with_stdio(false);
cin >> n;
for (register int i = 1; i <= n; i++)
cin >> p[i].x >> p[i].y;
for (register int i = 1; i <= n; i++)
points.insert(p[i]);
sort(p + 1, p + 1 + n);
solve(1, n);
cout << points.size() << endl;
for (set<Point>::iterator it = points.begin(); it != points.end(); it++)
cout << it->x << ' ' << it->y << endl;
return 0;
}