您的位置:首页 > 其它

CodeForces - 97B_Superset_分治

2018-01-27 19:51 351 查看

题意

给出平面上 n 个点的坐标(最多 1e4 个),要往其上增加若干点,使得加点后,平面上任意两点至少满足下列三条件之一:

1。两点横坐标相同

2。两点纵坐标相同

3。以两点为对角的矩形中(含边线),至少含义一个其他点。

要求新加入点不超过 2e5。

思路

首先找到中间那个点,即 mid = (1 + n) / 2。过这个点作一条垂直于 x 轴的直线,不在这条直线上的其他点在这条直线上的正投影都增加到平面上。增加之后,直线上任意一点和平面上现有的任意一点构成的点对必满足上述条件。并且,任意一对被直线分隔开的点,也必定满足上述条件。不被直线分隔的点对仍可能不满足条件。

所以,题目转化为确保任意两点之间至少有一条这样的直线分隔。用分治的思想解决。

经过第一步之后,原问题实际上分成了两个与原问题相同的子问题:直线左边的点 和 直线右边的点。情况与原问题相同。所以,递归地过每一个子问题中间的点作垂直于 x 轴的直线,将子问题中的其他点的投影加入,将子问题继续细分直到不可分。

这样最多加入 nlogn 个节点,必小于 2e5。完美解决。

链接

https://vjudge.net/contest/177348#problem/J

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>

using namespace std;

const int maxn = 1e4 + 10;

typedef pair<int, int> P;

int n;
P A[maxn];
set<P> se;
set<P>::iterator it;

void dfs(int l, int r)
{
int mid = (l + r) >> 1;
int x = A[mid].first;

for(int i = l; i <= r; i++)
se.insert(P(x, A[i].second));

if(l < mid) dfs(l, mid);
if(mid < r) dfs(mid + 1, r);
}

int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d %d", &A[i].first, &A[i].second);
sort(A + 1, A + n + 1);

dfs(1, n);

cout << se.size() << endl;

for(it = se.begin(); it != se.end(); it++)
cout << it->first << " " << it->second << endl;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: