【CF 475F】Meta-universe(启发式分裂)

传送门


题解:

一个显然的结论是最终分裂出来的状态的分裂的中间操作没有关系。

一个朴素的想法是按照两维排序之后扫一遍看是否有缺口。

一个简单的优化是,排序用set,分裂从四个方向搞,每次启发式分裂把小的拿出去。

十分好写,一发AC。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{
	inline char gc(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	template<typename T>
	inline T get(){
		char c;T num;bool f=0;
		while(!isdigit(c=gc()))f=c=='-';num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return f?-num:num;
	}
	inline int gi(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

struct Point{int x,y;};
struct cmp1{bool operator()(cs Point &a,cs Point &b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}};
struct cmp2{bool operator()(cs Point &a,cs Point &b){return a.y<b.y||(a.y==b.y&&a.x<b.x);}};

typedef std::set<Point,cmp1> Sx;
typedef std::set<Point,cmp2> Sy;

int ans;

inline void split(Sx &s1,Sy &s2){
	auto lx=s1.begin(),rx=--s1.end();
	auto ly=s2.begin(),ry=--s2.end();
	int n=s1.size()>>1;
	for(int re i=1;i<=n;++i){
		{
			auto tp=lx++;
			if(tp->x+1<lx->x){
				Sx s3;Sy s4;lx=++tp;
				for(tp=s1.begin();tp!=lx;){
					auto now=tp++;
					s3.insert(*now);
					s4.insert(*now);
					s2.erase(*now);
					s1.erase(now);
				}
				split(s1,s2);split(s3,s4);
				return ;
			}
		}
		{
			auto tp=rx--;
			if(tp->x-1>rx->x){
				Sx s3;Sy s4;rx=--tp;
				for(tp=--s1.end();tp!=rx;){
					auto now=tp--;
					s3.insert(*now);
					s4.insert(*now);
					s2.erase(*now);
					s1.erase(now);
				}
				split(s1,s2);split(s3,s4);
				return ;
			}
		}
		{
			auto tp=ly++;
			if(tp->y+1<ly->y){
				Sx s3;Sy s4;ly=++tp;
				for(tp=s2.begin();tp!=ly;){
					auto now=tp++;
					s4.insert(*now);
					s3.insert(*now);
					s1.erase(*now);
					s2.erase(now);
				}
				split(s1,s2);split(s3,s4);
				return ;
			}
		}
		{
			auto tp=ry--;
			if(tp->y-1>ry->y){
				Sx s3;Sy s4;ry=--tp;
				for(tp=--s2.end();tp!=ry;){
					auto now=tp--;
					s4.insert(*now);
					s3.insert(*now);
					s1.erase(*now);
					s2.erase(now);
				}
				split(s1,s2);split(s3,s4);
				return ;
			}
		}
	}++ans;
}

Sx sx;Sy sy;
signed main(){
#ifdef zxyoi
	freopen("meta.in","r",stdin);
#endif
	int n=gi();
	while(n--){
		int x=gi(),y=gi();
		sx.insert((Point){x,y});
		sy.insert((Point){x,y});
	}
	split(sx,sy);
	cout<<ans<<"\n";
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值