分治常见Trick——启发式分裂+中间相遇法:CF1181E2

https://www.luogu.com.cn/problem/CF1181E2

首先E1,也就是分治应该很好想

考虑到E2,首先看到题目是二维平面,有很多种分割方法,所以我们可以考虑拆维。

拆完之后我们考虑枚举分界点。枚举分界点暴力遍历过大,于是自然而然的,我们可以考虑中间相遇法。

但如果优雅的维护对应的集合呢?朴素思路使用set。考虑这个过程中会分裂成两个区间,一个小,一个大。暴力分裂似乎不太可惜,但我们可以考虑分出小的,保留大的,也就是启发式分裂。

#include<bits/stdc++.h>
using namespace std;
//#define int long long
inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
//mt19937 rand(time(0));
//mt19937_64 rand(time(0));
//srand(time(0));
#define N 100010
//#define M
//#define mo
struct node {
	int l, r, id; 
	bool operator <(const node &A) const {
		if(l==A.l) return id<A.id; 
		return l<A.l; 
	}
}c[N][4];
int n, m, i, j, k, T;
set<node>s[4]; 
int lx, ly, rx, ry; 

int solve(set<node>L[4]) {
	int i, j, p, k; 
	if(L[0].size()<=1) return 1; 
	set<node>R[4]; 
	set<node>::iterator it[4], t; 
	int mx[4]; 
	for(i=0; i<4; ++i) 
		it[i]=L[i].begin(), mx[i]=it[i]->r, ++it[i], R[i].clear(); 
	for(i=1; i<L[0].size(); ++i) {
		for(j=0; j<4; ++j) {
			if(it[j]->l>=mx[j]) {
				for(t=L[j].begin(); t!=it[j]; ) {
					p=t->id; ++t;
					for(k=0; k<4; ++k) 
						R[k].insert(c[p][k]),  
						L[k].erase(c[p][k]); 
				}
				return solve(L)	&& solve(R); 
			}
			mx[j]=max(mx[j], (it[j]->r)); ++it[j]; 
		}
	}
	return 0; 
}

signed main()
{
//	freopen("in.txt", "r", stdin);
//	freopen("out.txt", "w", stdout);
//	T=read();
//	while(T--) {
//
//	}
	n=read(); 
	for(i=1; i<=n; ++i) {
		lx=read(); ly=read(); rx=read(); ry=read(); 
		c[i][0]={lx, rx, i}; s[0].insert(c[i][0]); 
		c[i][1]={-rx, -lx, i}; s[1].insert(c[i][1]); 
		c[i][2]={ly, ry, i}; s[2].insert(c[i][2]); 
		c[i][3]={-ry, -ly, i}; s[3].insert(c[i][3]); 
//		printf("%d %d %d %d\n", (int)s[0].size(), s[1].size(), s[2].size(), s[3].size()); 

	}
//	printf("%d %d %d %d\n", s[0].size(), s[1].size(), s[2].size(), s[3].size()); 
	printf(solve(s) ? "YES\n" : "NO\n"); 
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值