题解洛谷 P8216【[THUPC2022 初赛] 画图】
大模拟,应该还算大模拟里面偏简单的。
正如官方题解说的,本题难点在于注意到这道题是可做题。
首先,一开始有 \(10^5\) 条线段,而 THUPC
只有 \(15\) 条,我们需要按照题意将“出现同方向线段的首尾相连、重叠或包含”,合并成一条线段。
这部分比较好处理,以方向为第一关键字,然后 \(x\) 或者 \(y\) 为第二关键字,最后 \(l\) 或者 \(d\) 为第三关键字排序。然后按顺序枚举线段,方向不同必然是新的线段,如果 \(x\) 或者 \(y\) 不同也是,否则根据 \(l,r\) 或者 \(u,d\) 判断是否“首尾相连、重叠或包含”,进行处理即可。
之后如果不是恰好 \(15\) 条线段,那么就是 No
。
然后数据规模缩小到了 \(15\),属于是咋做都行了。我们跑一遍洪水填充,把每个连通块标记出来,看一眼是不是恰好 \(5\) 个连通块,不是就是 No
。
接着判断这 \(5\) 个连通块的大小是不是 \(2,3,3,3,4\)(顺序可打乱),如果不是也是 No
。
继续判断就需要抓特征。可以先判断大小为 \(2\) 的连通块是不是 T
,然后判断大小为 \(4\) 的连通块是不是 P
。我们还观察到,剩余的连通块里只有 C
有两条横向线段。这些都可以根据题目的要求判掉。最后剩下的 U
和 H
类似判一下,拿 bool 变量存一下就好了。
如果恰好是 THUPC
,就 Yes
;否则 No
。
赛时代码:
//By: Luogu@rui_er(122461) & registerGen(242702)
//Team: 世一大附中老同志
#include
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
#define debug printf("Running %s on line %d...\n",__FUNCTION__,__LINE__)
#define fileIO(s) do{freopen(s".in","r",stdin);freopen(s".out","w",stdout);}while(false)
using namespace std;
typedef long long ll;
const int N = 1e5+5;
int n, vis[N], sz[N];
#define No do{return puts("No")&0;}while(0)
#define Yes do{return puts("Yes")&0;}while(0)
template void chkmin(T& x, T y) {if(x > y) x = y;}
template void chkmax(T& x, T y) {if(x < y) x = y;}
struct Segment {
int op, l, r, u, d;
Segment(int op=0, int a=0, int b=0, int c=0, int d=0) : op(op), l(a), r(b), u(c), d(d) {}
~Segment() {}
friend bool operator < (const Segment& a, const Segment& b) {
if(a.op != b.op) return a.op < b.op;
if(!a.op) {
if(a.u != b.u) return a.u < b.u;
return a.l < b.l;
}
else {
if(a.l != b.l) return a.l < b.l;
return a.d < b.d;
}
}
}a[N], b[N];
bool intersect(Segment a, Segment b) {
if(a.op == b.op) return 0;
if(a.op > b.op) swap(a, b);
if(b.l < a.l || b.l > a.r) return 0;
if(a.u > b.u || a.u < b.d) return 0;
return 1;
}
void dfs_floodfill(int u, int c) {
vis[u] = c;
++sz[c];
rep(i, 1, 15) {
if(i == u || vis[i]) continue;
if(intersect(b[i], b[u])) {
dfs_floodfill(i, c);
}
}
}
int main() {
scanf("%d", &n);
rep(i, 1, n) {
int op, A, B, C;
scanf("%d%d%d%d", &op, &A, &B, &C);
if(!op) a[i] = Segment(op, A, B, C, C);
else a[i] = Segment(op, C, C, B, A);
}
sort(a+1, a+1+n);
int tot = 1;
b[1] = a[1];
rep(i, 2, n) {
if(a[i].op != b[tot].op) b[++tot] = a[i];
else if(!a[i].op) {
if(a[i].u == b[tot].u) {
if(b[tot].r >= a[i].l) chkmax(b[tot].r, a[i].r);
else b[++tot] = a[i];
}
else b[++tot] = a[i];
}
else {
if(a[i].l == b[tot].l) {
if(b[tot].u >= a[i].d) chkmax(b[tot].u, a[i].u);
else b[++tot] = a[i];
}
else b[++tot] = a[i];
}
}
// rep(i, 1, tot) printf("%d %d %d %d %d\n", b[i].op, b[i].l, b[i].r, b[i].u, b[i].d);
if(tot != 15) No;
int totc = 0;
rep(i, 1, 15) {
if(!vis[i]) dfs_floodfill(i, ++totc);
}
if(totc != 5) No;
int buc[5] = {0, 0, 0, 0, 0};
rep(i, 1, 5) {
if(sz[i] < 2 || sz[i] > 4) No;
++buc[sz[i]];
}
if(buc[2] != 1 || buc[3] != 3 || buc[4] != 1) No;
int H = 0, U = 0;
rep(i, 1, 5) {
// printf("COLOR %d: ", i);
if(sz[i] == 2) { // T
int ok = 0;
rep(j, 1, 15) { // - 1
if(vis[j] != i || b[j].op) continue;
rep(k, 1, 15) { // | 2
if(vis[k] != i || !b[k].op) continue;
if(b[k].d < b[j].u
&& b[j].u == b[k].u
&& b[j].l < b[k].l
&& b[k].l < b[j].r)
ok = 1;
}
}
if(!ok) No;
// puts("T");
}
else if(sz[i] == 4) { // P
int ok = 0;
rep(j, 1, 15) { // | long 9
if(vis[j] != i || !b[j].op) continue;
rep(k, 1, 15) { // | short 12
if(vis[k] != i || !b[k].op) continue;
if(j == k || b[j].u - b[j].d <= b[k].u - b[k].d) continue;
rep(l, 1, 15) { // - up 10
if(vis[l] != i || b[l].op) continue;
rep(m, 1, 15) { // - down 11
if(l == m || vis[m] != i || b[m].op) continue;
if(b[j].d < b[m].d
&& b[m].d == b[k].d
&& b[k].d < b[j].u
&& b[j].u == b[l].u
&& b[l].u == b[k].u
&& b[j].l == b[l].l
&& b[l].l == b[m].l
&& b[m].l < b[l].r
&& b[l].r == b[m].r
&& b[m].r == b[k].l)
ok = 1;
}
}
}
}
if(!ok) No;
// puts("P");
}
else { // H | U | C
int _ = 0; // -
rep(j, 1, 15) {
if(!b[j].op && vis[j] == i) {
++_;
}
}
if(_ == 2) { // C
int ok = 0;
rep(j, 1, 15) { // | 13
if(vis[j] != i || !b[j].op) continue;
rep(k, 1, 15) { // - up 14
if(vis[k] != i || b[k].op) continue;
rep(l, 1, 15) { // - down 15
if(k == l || vis[l] != i || b[l].op) continue;
if(b[l].d >= b[k].d) continue;
if(b[j].d == b[l].d
&& b[l].d < b[j].u
&& b[j].u == b[k].d
&& b[j].l == b[k].l
&& b[k].l == b[l].l
&& b[l].l < b[k].r
&& b[k].r == b[l].r)
ok = 1;
}
}
}
if(!ok) No;
// puts("C");
}
else {
// H
int okH = 0;
rep(j, 1, 15) { // | left 3
if(vis[j] != i || !b[j].op) continue;
rep(k, 1, 15) { // - 4
if(vis[k] != i || b[k].op) continue;
rep(l, 1, 15) { // | right 5
if(j == l || vis[l] != i || !b[l].op) continue;
if(b[l].l <= b[j].l) continue;
if(b[j].d == b[l].d
&& b[l].d < b[k].d
&& b[k].d < b[j].u
&& b[j].u == b[l].u
&& b[j].l == b[k].l
&& b[k].l < b[k].r
&& b[k].r == b[l].l)
okH = 1;
}
}
}
// U
int okU = 0;
rep(j, 1, 15) { // | left 6
if(vis[j] != i || !b[j].op) continue;
rep(k, 1, 15) { // - 7
if(vis[k] != i || b[k].op) continue;
rep(l, 1, 15) { // | right 8
if(j == l || vis[l] != i || !b[l].op) continue;
if(b[l].l <= b[j].l) continue;
if(b[j].d == b[l].d
&& b[l].d == b[k].d
&& b[k].d < b[j].u
&& b[j].u == b[l].u
&& b[j].l == b[k].l
&& b[k].l < b[k].r
&& b[k].r == b[l].l)
okU = 1;
}
}
}
H |= okH;
U |= okU;
// if(okH) puts("H");
// if(okU) puts("U");
}
}
}
if(H && U) Yes;
else No;
return 0;
}