solution:
考点:数学 + 2-sat 模型。
观察
k
≤
4
k\leq 4
k≤4 肯定有猫腻。
设所有正方形的右边界最小值为
m
n
x
mnx
mnx 。
则可以证明若有解一定存在一个竹签使得其纵坐标为
m
n
x
mnx
mnx ,即调整坐标得到不劣的方案。
类似的也有同样的性质。对于
k
≤
3
k\leq 3
k≤3 的情况,根据鸽巢原理,一定存在一个竹签落在四个角上。直接
O
(
4
k
n
)
O(4^kn)
O(4kn) 爆搜即可。
对于
k
=
4
k=4
k=4 的情况,正确考虑方式为:如果一个矩形如果和三条直线相交,那么一定包含一条边界,可以不用考虑;否则考虑 2-sat 模型。限制条件为:若两个区间不存在交,则一定不能被同一条边覆盖。
那我们可以把 l, r 端点分别 push_back 进每一个可能满足的边,对于每个 l, 向满足 r<l 的点建边,同理,对于每个 r,向满足 l>r 的点建边。可以 two-pointers 完成。这样要构造 2*3=6 倍节点。
时间复杂度
O
(
n
(
l
o
g
n
+
4
k
)
)
O(n(logn+4^k))
O(n(logn+4k)) 。代码好恶心。
代码是
z
y
y
zyy
zyy 的,做了一些改动。
d
e
b
u
g
debug
debug 了一晚上终于改对了代码。
#include <bits/stdc++.h>
#define PII pair<int,int>
#define INF 0x3f3f3f3f
#define ll long long
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
using namespace std;
const int mx = 2e5 + 5;
const int mxn = mx * 6;
int n, k, nd, cnt[mx], id[mx][2], pr[mx], su[mx], at[mx][2];
int dfn[mxn], low[mxn], vis[mxn], c[mxn], s[mxn], tp, bl, num;
struct qry {
int x, v0, v1;
bool operator <(const qry &a) const {
return x < a.x;
}
};
vector<qry> vl[4], vr[4];
vector<int> g[mxn];
PII ans[5];
struct node {
int x, y, x2, y2;
} a[mx];
void add(int x, int y) {
if (!x || !y)
return;
g[x].push_back(y);
}
void change(int x, int y, int r) {
for (int i = 1; i <= n; i++) {
if (a[i].x <= x && x <= a[i].x2 && a[i].y <= y && y <= a[i].y2) {
cnt[i] += r;
}
}
}
void dfs(int d) {
int mnx = 1e9, mxx = 1;
int mny = 1e9, mxy = 1;
for (int i = 1; i <= n; i++) {
if (!cnt[i]) {
mnx = min(mnx, a[i].x2);
mxx = max(mxx, a[i].x);
mny = min(mny, a[i].y2);
mxy = max(mxy, a[i].y);
}
}
if (d == 1) {
if (mxx <= mnx && mxy <= mny) {
printf("%d %d\n", mnx, mny);
for (int i = 2; i <= k; i++) {
printf("%d %d\n", ans[i].fi, ans[i].se);
}
exit(0);
}
return;
}
int a[2] = {mnx, mxx}, b[2] = {mny, mxy};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
ans[d] = make_pair(a[i], b[j]);
change(a[i], b[j], 1), dfs(d - 1), change(a[i], b[j], -1);
}
}
}
void tarjan(int x) {
dfn[x] = low[x] = ++num, vis[x] = 1, s[++tp] = x;
for (auto y : g[x]) {
if (!dfn[y])
tarjan(y), low[x] = min(low[x], low[y]);
else if (vis[y])
low[x] = min(low[x], dfn[y]);
}
if (low[x] == dfn[x]) {
int tmp(0);
bl++;
do {
tmp = s[tp--];
c[tmp] = bl;
vis[tmp] = 0;
} while (tmp != x);
}
}
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) {
scanf("%d%d%d%d", &a[i].x, &a[i].y, &a[i].x2, &a[i].y2);
}
dfs(k);
int mnx = 1e9, mxx = 1;
int mny = 1e9, mxy = 1;
For(i, 1, n) {
mnx = min(mnx, a[i].x2);
mxx = max(mxx, a[i].x);
mny = min(mny, a[i].y2);
mxy = max(mxy, a[i].y);
}
if (mnx > mxx)
swap(mnx, mxx);
if (mny > mxy)
swap(mny, mxy);
For(i, 1, n) {
a[i].x = max(a[i].x, mnx);
a[i].x2 = min(a[i].x2, mxx);
a[i].y = max(a[i].y, mny);
a[i].y2 = min(a[i].y2, mxy);
}
for (int i = 1; i <= n; i++) {
int fl = 0, s = 0, d = 0;
if (a[i].x <= mnx && mnx <= a[i].x2)
fl |= 1, s++;
if (a[i].x <= mxx && mxx <= a[i].x2)
fl |= 2, s++;
if (a[i].y <= mny && mny <= a[i].y2)
fl |= 4, s++;
if (a[i].y <= mxy && mxy <= a[i].y2)
fl |= 8, s++;
if (s >= 3)
continue;
if (s == 0)
return 0;
id[i][0] = ++nd;
id[i][1] = ++nd;
if (s == 1)
g[nd].push_back(nd - 1);
for (int j = 0; j <= 3; j++) {
if (fl >> j & 1) {
at[i][d] = j;
if (j & 2) {
vl[j].push_back({a[i].x, id[i][d], id[i][d ^ 1]});
vr[j].push_back({a[i].x2, id[i][d], id[i][d ^ 1]});
d++;
} else {
vl[j].push_back({a[i].y, id[i][d], id[i][d ^ 1]});
vr[j].push_back({a[i].y2, id[i][d], id[i][d ^ 1]});
d++;
}
}
}
}
for (int i = 0; i <= 3; i++) {
if (!vl[i].size())
continue;
int sz = vl[i].size(), pos = 0;
sort(vl[i].begin(), vl[i].end());
sort(vr[i].begin(), vr[i].end());
pr[0] = su[sz + 1] = 0;
for (int j = 1; j <= sz; j++) {
pr[j] = ++nd;
add(pr[j], pr[j - 1]);
add(pr[j], vr[i][j - 1].v1);
}
for (int j = sz; j >= 1; j--) {
su[j] = ++nd;
add(su[j], su[j + 1]);
add(su[j], vl[i][j - 1].v1);
}
for (int j = 0; j < sz; j++) {
for (; pos < sz && vl[i][j].x > vr[i][pos].x; pos++);
add(vl[i][j].v0, pr[pos]);
}
pos = 0;
for (int j = 0; j < sz; j++) {
for (; pos < sz && vr[i][j].x >= vl[i][pos].x; pos++);
add(vr[i][j].v0, su[pos + 1]);
}
}
for (int i = 1; i <= nd; i++) {
if (!dfn[i])
tarjan(i);
}
for (int i = 1; i <= n; i++) {
if (id[i][0] && c[id[i][0]] == c[id[i][1]]) {
printf("-1");
return 0;
}
}
int mn[4], mx[4];
For(i, 0, 3) {
mn[i] = (i & 2 ? mnx : mny);
mx[i] = (i & 2 ? mxx : mxy);
}
For(i, 1, n) if (id[i][0]) {
int flg = (c[id[i][0]] > c[id[i][1]]);
int idd = at[i][flg];
mn[idd] = max(mn[idd], (idd & 2 ? a[i].x : a[i].y));
mx[idd] = max(mx[idd], (idd & 2 ? a[i].x2 : a[i].y2));
}
printf("%d %d\n", mnx, mn[0]);
printf("%d %d\n", mxx, mn[1]);
printf("%d %d\n", mn[2], mny);
printf("%d %d\n", mn[3], mxy);
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」