题目 K : 点
题目描述
平面上有 n 个点(任意两点的横坐标与纵坐标都不会相同),每个点向 x 轴 和 y 轴做垂线分别形成两个交点,两个交点和该点以及坐标原点构成一个矩形,并覆盖矩形内的点(在边缘上的点不算被覆盖),请输出平面上所有一次也没有被覆盖过的点。
输入
第一行一个正整数 T(T<=5),表示共有 T 组数据。
每组数据的第一行一个正整数数 n(1<=n<= 200000),表示平面上有 n 个点。
接下来 n 行每行两个正整数 x,y(1<=x,y<= 1e9)表示一个点的横纵坐标。
输出
按 x 轴坐标从小到大输出所有符合条件的点。
样例输入
1
5
8 1
17 5
9 6
12 11
13 7
样例输出
12 11
13 7
17 5
解题思路
这道题的难点在如何降低复杂度,否则会轻易的超时,其实还可以这样去解,我们对输入的坐标点从小到大排序(按照x),那么我们就可以得到,这样我们将x已经约束,所以只需要看当前坐标的纵坐标只要小于最大值,那么这个点一定会被覆盖的,如果不好理解手动排序一下,很容易看出来。
参考代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define MAX_LEN 200005
using namespace std;
typedef struct POINT{
int x;
int y;
bool isFill;
}Point;
int cmp(Point a, Point b)
{
return a.x < b.x;
}
Point point[MAX_LEN];
int main()
{
int t;
scanf("%d\n",&t);
while (t--)
{
int n;
scanf("%d\n",&n);
memset(point, 0, sizeof(point));
for(int i=0; i<n; i++)
{
scanf("%d%d",&point[i].x,&point[i].y);
}
sort(point, point+n, cmp);//排序,按照x从小到大排序
int x_min = 1e9 + 5;
int y_max = 0;
for(int i=n-1; i>=0; i--)//从大到小遍历,因为x已经被约束
{
if(point[i].x < x_min && point[i].y <y_max)//判断点是否被填充
{
point[i].isFill = true;//填充
}
x_min = min(x_min,point[i].x);//更新x_min
y_max = max(y_max,point[i].y);//更新y_max
}
for(int i=0;i<n;i++)//因为是x从小到大输出
{
if(!point[i].isFill)//没有被填充
{
printf("%d %d\n",point[i].x,point[i].y);
}
}
}
return 0;
}