Loading

CF97B Superset超级集合

CF97B Superset

这题主要是构造难想。看看数据范围发现连\(O(n^2)\)都被卡了,然后 考试的名称提醒我 想到了分治。

坐标按横坐标为关键字排序后找中间的点进行分治不是点分治qwq

考虑让中间点作一条平行于y轴的直线,让每个点i(mid除外)向这条直线引垂线交于一个点 \(S_i\),那么这个点一定可以加入。

原因:

可行性证明:

考虑不包含 \(S_i\) 的点,由于左半边和右半边都已满足条件,当左边的点i和右边的点j组成矩形时,矩形边缘上一定有2个点\(S_i,S_j\),于是这些S就能使左右合并。

考虑包含 \(S_i\) 的点。如果它和点j组成矩形,那么边缘上一定有点 \(S_j\) ,满足题意。

分治完了记得去重哦~

由于点数是 \(n\log n\) 的级别,所以数组也要开到 \(n\log n\)

#include<bits/stdc++.h>
using namespace std;
const int N=150005;
int n,len,tot;
struct point{
	int x,y;
}a[N],ans[N],p[N];
bool cmp(const point &a,const point &b)
{
	if(a.x!=b.x)return a.x<b.x;
	else return a.y<b.y;
}
void msort(int l,int r)
{
	if(l==r){ans[++tot]=a[l];return;}
	if(l>r)return;
	int mid=(l+r)>>1;
	msort(l,mid-1);msort(mid+1,r);
	for(int i=l;i<=r;++i)
	{
		point tmp;
		tmp.x=a[mid].x;
		tmp.y=a[i].y;
		ans[++tot]=tmp;
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		scanf("%d%d",&a[i].x,&a[i].y);
	sort(a+1,a+n+1,cmp);
	msort(1,n);
	sort(ans+1,ans+tot+1,cmp);
	ans[0].x=ans[0].y=1000000007;
	for(int i=1;i<=tot;++i)
	{
		if(ans[i].x!=ans[i-1].x||ans[i].y!=ans[i-1].y)
			p[++len]=ans[i];
	}
	printf("%d\n",len);
	for(int i=1;i<=len;++i)
		printf("%d %d\n",p[i].x,p[i].y);
	return 0;
}
posted @ 2020-02-23 16:28  zzctommy  阅读(224)  评论(0编辑  收藏  举报