考虑优雅地去实现这道模拟题(代码 \(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;
}