P8216

发布时间 2023-11-12 13:05:00作者: mRXxy0o0

考虑优雅地去实现这道模拟题(代码 \(2.5KB\))。

分析

最大的难点真的就是记住每一个限制(读错题导致差点写了线段树)。这里提取最关键的两个:有交且同向的线段会合并、每个字母的组成线段不能有交

首先,合并一下线段,三关键字排序即可。这里可以复用原数组减少空间及码量。合并完判断一下,应该刚好 \(15\) 条线段,其中 \(7\)\(8\) 竖。

其次,利用一下第二个限制,可以得到:线段间有交的必然在同一个字母。这里用一个并查集简单地去维护。注意要记录一下每个联通块的大小,方便后面判断。

最后,按照边数分类,依次判断能否组成指定字母即可。

思路比较清晰,唯一难点可能是在最后一步的判断上,作为本篇题解唯一暴力模拟的地方,照着题面慢慢敲式子就好(赞美良心出题人)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,rx[6]={0,1,1,1,2,2},ry[6]={0,1,2,2,2,1};
int n,tot,cx,cy,num,fa[N],cnt[N];
bool fg[N];
vector<pii>hav;
struct node{
	int op,l,r,x;
}a[N],lx[N],ly[N];
inline bool cmp(node x,node y){
	return x.op==y.op?(x.x==y.x?x.l<y.l:x.x<y.x):x.op<y.op;
}
inline int gf(int x){
	return fa[x]==x?x:fa[x]=gf(fa[x]);
}
inline bool check(int p,int tp){
	cx=cy=0;
	for(int i=1;i<=n;++i){
		if(gf(i)==hav[p].second){
			if(a[i].op) ly[++cy]=a[i];
			else lx[++cx]=a[i];
		}
	}
	if(cx!=rx[tp]||cy!=ry[tp]) return 0;
	switch (tp){
		case 1:
			return ly[1].l<lx[1].x&&lx[1].x==ly[1].r&&lx[1].l<ly[1].x&&ly[1].x<lx[1].r;
		case 2:
			return ly[1].l==ly[2].l&&ly[2].l<lx[1].x&&lx[1].x<ly[1].r&&ly[1].r==ly[2].r&&ly[1].x==lx[1].l&&lx[1].l<lx[1].r&&lx[1].r==ly[2].x;
		case 3:
			return ly[1].l==ly[2].l&&ly[2].l==lx[1].x&&lx[1].x<ly[1].r&&ly[1].r==ly[2].r&&ly[1].x==lx[1].l&&lx[1].l<lx[1].r&&lx[1].r==ly[2].x;
		case 4:
			return ly[1].l<lx[1].x&&lx[1].x==ly[2].l&&ly[2].l<ly[1].r&&ly[1].r==ly[2].r&&ly[2].r==lx[2].x&&ly[1].x==lx[1].l&&lx[1].l==lx[2].l&&lx[2].l<lx[2].r&&lx[2].r==lx[1].r&&lx[1].r==ly[2].x;
		case 5:
			return ly[1].l==lx[1].x&&lx[1].x<ly[1].r&&ly[1].r==lx[2].x&&ly[1].x==lx[1].l&&ly[1].x==lx[2].l&&lx[2].l<lx[2].r&&lx[2].r==lx[1].r;
	}
	return 0;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d%d%d%d",&a[i].op,&a[i].l,&a[i].r,&a[i].x);
	}
	sort(a+1,a+1+n,cmp);
	tot=1;
	for(int i=1;i<=n;++i){
		if(a[i].op!=a[tot].op||a[i].x!=a[tot].x||a[i].l>a[tot].r) a[++tot]=a[i];
		else a[tot].r=max(a[tot].r,a[i].r);
	}
	if(tot!=15) return puts("No"),0;
	n=tot;
	for(int i=1;i<=n;++i){
		if(!a[i].op) ++cx;
		else ++cy;
		fa[i]=i;
		cnt[i]=1;
	}
	if(cx!=7||cy!=8) return puts("No"),0;
	for(int i=1;i<=cx;++i){
		for(int j=cx+1;j<=n;++j){
			if(a[i].l<=a[j].x&&a[j].x<=a[i].r&&a[j].l<=a[i].x&&a[i].x<=a[j].r){
				int fx=gf(i),fy=gf(j);
				if(fx!=fy){
					fa[fx]=fy;
					cnt[fy]+=cnt[fx];
				}
			}
		}
	}
	for(int i=1;i<=n;++i){
		if(gf(i)==i) hav.push_back({cnt[i],i});
	}
	sort(hav.begin(),hav.end());
	if(hav.size()!=5||hav[0].first!=2||hav[1].first!=3||hav[2].first!=3||hav[3].first!=3||hav[4].first!=4) return puts("No"),0;
	if(check(0,1)&&check(4,4)&&((check(1,2)&&check(2,3)&&check(3,5))||(check(1,2)&&check(3,3)&&check(2,5))||(check(2,2)&&check(1,3)&&check(3,5))||(check(2,2)&&check(3,3)&&check(1,5))||(check(3,2)&&check(1,3)&&check(2,5))||(check(3,2)&&check(2,3)&&check(1,5)))) puts("Yes");
	else puts("No");
	return 0;
}