「JOISC 2020 Day1」汉堡肉
考虑一维的情况,我们选择的最左边那个点一定是所有线段的 ,因为要在没有任何线段在它左边的情况下使得左端点尽量靠右。同理最右边那个点一定是所有线段的 。
因此枚举选这两个点中的哪个,删去与这个点有交的线段,递归深搜即可。
扩展到二维的情况,最上面那个点一定是 ,最下面是 ,最左边是 ,最右边是 。
我们称 坐标 和 以及 坐标 和 的线段为关键线段。最后选择的点一定在四条关键线段构成的矩形上,且四条关键线段上一定有点被选择。
对于 的情况,三个点却要覆盖四条线段,显然需要选择交点。枚举四个选哪个,按上述方法深搜,复杂度 。
先深搜看看有没出解,如果没有再继续讨论。
对于每个矩形,如果与 条及以上关键线段相交,那么内部至少一个点,不用管。
如果只与 条相交,那么这条关键线段上的点必定落在与这条关键线段相交的区间内。
如果与 条相交,那么两条相交线段必有一处上有点,典型 2-SAT。
图中两条黄色括起来的线段至少有一个内部有点。
每条关键线段上的线段按右端点排序,二分找到第一个右端点比当前线段左端点还小的点,前缀优化建图即可。
代码及其好写,也就 10KB+嘛,比别人长了两三倍而已
#include <cstdio>
#include <vector>
#include <algorithm>
#define gc (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 65536, stdin), p1 == p2) ? EOF : *p1 ++)
inline int min(const int x, const int y) {return x < y ? x : y;}
inline int max(const int x, const int y) {return x > y ? x : y;}
char buf[65536], *p1, *p2;
inline int read() {
char ch;
int x = 0;
while ((ch = gc) < 48);
do x = x * 10 + ch - 48; while ((ch = gc) >= 48);
return x;
}
int l[200005], r[200005], d[200005], u[200005], tl[200005], tr[200005], td[200005], tu[200005];
int l2[5][200005], r2[5][200005], d2[5][200005], u2[5][200005];
int a[5], b[5];
int n, k, left = 1e9, right, down = 1e9, up, now, cnt = 1;
std::vector<int> rect;
bool dfs(int step) {
if (!now) {
for (int i = 1; i < step; ++ i) printf("%d %d\n", a[i], b[i]);
for (int i = step; i <= k; ++ i) puts("1 1");
return true;
}
if (step > k) return false;
int left = 2e9, right = 0, down = 2e9, up = 0;
for (int i = 1; i <= now; ++ i) {
right = max(right, l[i]);
up = max(up, d[i]);
left = min(left, r[i]);
down = min(down, u[i]);
}
int tmp = 0, tnow = now;
a[step] = left, b[step] = down;
for (int i = 1; i <= now; ++ i)
l2[step][i] = l[i], r2[step][i] = r[i], d2[step][i] = d[i], u2[step][i] = u[i];
for (int i = 1; i <= now; ++ i)
if (!(l[i] <= left && left <= r[i] && d[i] <= down && down <= u[i]))
tl[++ tmp] = l[i], tr[tmp] = r[i], td[tmp] = d[i], tu[tmp] = u[i];
now = tmp;
for (int i = 1; i <= now; ++ i) l[i] = tl[i], r[i] = tr[i], d[i] = td[i], u[i] = tu[i];
if (dfs(step + 1)) return true;
now = tnow;
for (int i = 1; i <= now; ++ i)
l[i] = l2[step][i], r[i] = r2[step][i], d[i] = d2[step][i], u[i] = u2[step][i];
a[step] = left, b[step] = up, tmp = 0;
for (int i = 1; i <= now; ++ i)
if (!(l[i] <= left && left <= r[i] && d[i] <= up && up <= u[i]))
tl[++ tmp] = l[i], tr[tmp] = r[i], td[tmp] = d[i], tu[tmp] = u[i];
now = tmp;
for (int i = 1; i <= now; ++ i) l[i] = tl[i], r[i] = tr[i], d[i] = td[i], u[i] = tu[i];
if (dfs(step + 1)) return true;
now = tnow;
for (int i = 1; i <= now; ++ i)
l[i] = l2[step][i], r[i] = r2[step][i], d[i] = d2[step][i], u[i] = u2[step][i];
a[step] = right, b[step] = down, tmp = 0;
for (int i = 1; i <= now; ++ i)
if (!(l[i] <= right && right <= r[i] && d[i] <= down && down <= u[i]))
tl[++ tmp] = l[i], tr[tmp] = r[i], td[tmp] = d[i], tu[tmp] = u[i];
now = tmp;
for (int i = 1; i <= now; ++ i) l[i] = tl[i], r[i] = tr[i], d[i] = td[i], u[i] = tu[i];
if (dfs(step + 1)) return true;
now = tnow;
for (int i = 1; i <= now; ++ i)
l[i] = l2[step][i], r[i] = r2[step][i], d[i] = d2[step][i], u[i] = u2[step][i];
a[step] = right, b[step] = up, tmp = 0;
for (int i = 1; i <= now; ++ i)
if (!(l[i] <= right && right <= r[i] && d[i] <= up && up <= u[i]))
tl[++ tmp] = l[i], tr[tmp] = r[i], td[tmp] = d[i], tu[tmp] = u[i];
now = tmp;
for (int i = 1; i <= now; ++ i) l[i] = tl[i], r[i] = tr[i], d[i] = td[i], u[i] = tu[i];
if (dfs(step + 1)) return true;
now = tnow;
for (int i = 1; i <= now; ++ i)
l[i] = l2[step][i], r[i] = r2[step][i], d[i] = d2[step][i], u[i] = u2[step][i];
return false;
}
namespace TwoSAT {
struct Edge {
int to, nxt;
} e[10000005];
const int N = 2000000;
int head[N], s[N], dfn[N], low[N], col[N], tot, top, cnt, scc, n;
bool Instack[N];
inline void AddEdge(const int u, const int v) {
e[++ tot].to = v, e[tot].nxt = head[u], head[u] = tot;
}
void Tarjan(int u) {
dfn[u] = low[u] = ++ cnt, s[++ top] = u, Instack[u] = true;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (!dfn[v]) Tarjan(v), low[u] = min(low[u], low[v]);
else if (Instack[v]) low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
++ scc;
do
col[s[top]] = scc, Instack[s[top]] = false;
while (s[top --] != u);
}
}
std::vector<int> solve() {
std::vector<int> result;
for (int i = 2; i <= n; ++ i)
if (!dfn[i]) Tarjan(i);
for (int i = 2; i <= n; i += 2)
result.push_back(col[i] < col[i ^ 1] ? i : i ^ 1);
return result;
}
};
struct Line {
int l, r, x1, x2;
inline bool operator < (const Line a) const {return r < a.r;}
inline bool operator < (const int x) {return r < x;}
} L[200005], R[200005], D[200005], U[200005];
int prel1[200005], prel2[200005], prer1[200005], prer2[200005];
int pred1[200005], pred2[200005], preu1[200005], preu2[200005];
int type[1000005], lb[1000005], rb[1000005];
int cntl, cntr, cntd, cntu;
std::vector<int> ans;
int main() {
now = n = read(), k = read();
for (int i = 1; i <= n; ++ i) {
right = max(right, l[i] = l2[0][i] = read());
up = max(up, d[i] = d2[0][i] = read());
left = min(left, r[i] = r2[0][i] = read());
down = min(down, u[i] = u2[0][i] = read());
}
if (dfs(1)) return 0;
for (int i = 1; i <= n; ++ i)
l[i] = l2[0][i], r[i] = r2[0][i], d[i] = d2[0][i], u[i] = u2[0][i];
for (int i = 1; i <= n; ++ i) {
int num = 0;
if (l[i] <= left && left <= r[i]) ++ num;
if (l[i] <= right && right <= r[i]) ++ num;
if (d[i] <= down && down <= u[i]) ++ num;
if (d[i] <= up && up <= u[i]) ++ num;
if (num >= 3) continue;
if (num == 1) {
if (l[i] <= left && left <= r[i]) {
L[++ cntl] = Line{d[i], u[i], cnt + 1, cnt + 2};
type[cnt + 1] = 1, lb[cnt + 1] = d[i], rb[cnt + 1] = u[i];
}
if (l[i] <= right && right <= r[i]) {
R[++ cntr] = Line{d[i], u[i], cnt + 1, cnt + 2};
type[cnt + 1] = 2, lb[cnt + 1] = d[i], rb[cnt + 1] = u[i];
}
if (d[i] <= down && down <= u[i]) {
D[++ cntd] = Line{l[i], r[i], cnt + 1, cnt + 2};
type[cnt + 1] = 3, lb[cnt + 1] = l[i], rb[cnt + 1] = r[i];
}
if (d[i] <= up && up <= u[i]) {
U[++ cntu] = Line{l[i], r[i], cnt + 1, cnt + 2};
type[cnt + 1] = 4, lb[cnt + 1] = l[i], rb[cnt + 1] = r[i];
}
TwoSAT::AddEdge(cnt + 2, cnt + 1), cnt += 2;
} else rect.push_back(i);
}
for (int i : rect) {
bool lf = l[i] <= left && left <= r[i], rf = l[i] <= right && right <= r[i];
bool df = d[i] <= down && down <= u[i], uf = d[i] <= up && up <= u[i];
if (lf && rf) {
type[cnt + 1] = 1, lb[cnt + 1] = d[i], rb[cnt + 1] = u[i];
L[++ cntl] = Line{d[i], u[i], cnt + 1, cnt + 2}, cnt += 2;
type[cnt + 1] = 2, lb[cnt + 1] = d[i], rb[cnt + 1] = u[i];
R[++ cntr] = Line{d[i], u[i], cnt + 1, cnt + 2}, cnt += 2;
TwoSAT::AddEdge(L[cntl].x2, R[cntr].x1);
TwoSAT::AddEdge(R[cntr].x2, L[cntl].x1);
}
else if (lf && df) {
type[cnt + 1] = 1, lb[cnt + 1] = d[i], rb[cnt + 1] = u[i];
L[++ cntl] = Line{d[i], u[i], cnt + 1, cnt + 2}, cnt += 2;
type[cnt + 1] = 3, lb[cnt + 1] = l[i], rb[cnt + 1] = r[i];
D[++ cntd] = Line{l[i], r[i], cnt + 1, cnt + 2}, cnt += 2;
TwoSAT::AddEdge(L[cntl].x2, D[cntd].x1);
TwoSAT::AddEdge(D[cntd].x2, L[cntl].x1);
}
else if (lf && uf) {
type[cnt + 1] = 1, lb[cnt + 1] = d[i], rb[cnt + 1] = u[i];
L[++ cntl] = Line{d[i], u[i], cnt + 1, cnt + 2}, cnt += 2;
type[cnt + 1] = 4, lb[cnt + 1] = l[i], rb[cnt + 1] = r[i];
U[++ cntu] = Line{l[i], r[i], cnt + 1, cnt + 2}, cnt += 2;
TwoSAT::AddEdge(L[cntl].x2, U[cntu].x1);
TwoSAT::AddEdge(U[cntu].x2, L[cntl].x1);
}
else if (rf && df) {
type[cnt + 1] = 2, lb[cnt + 1] = d[i], rb[cnt + 1] = u[i];
R[++ cntr] = Line{d[i], u[i], cnt + 1, cnt + 2}, cnt += 2;
type[cnt + 1] = 3, lb[cnt + 1] = l[i], rb[cnt + 1] = r[i];
D[++ cntd] = Line{l[i], r[i], cnt + 1, cnt + 2}, cnt += 2;
TwoSAT::AddEdge(R[cntr].x2, D[cntd].x1);
TwoSAT::AddEdge(D[cntd].x2, R[cntr].x1);
}
else if (rf && uf) {
type[cnt + 1] = 2, lb[cnt + 1] = d[i], rb[cnt + 1] = u[i];
R[++ cntr] = Line{d[i], u[i], cnt + 1, cnt + 2}, cnt += 2;
type[cnt + 1] = 4, lb[cnt + 1] = l[i], rb[cnt + 1] = r[i];
U[++ cntu] = Line{l[i], r[i], cnt + 1, cnt + 2}, cnt += 2;
TwoSAT::AddEdge(R[cntr].x2, U[cntu].x1);
TwoSAT::AddEdge(U[cntu].x2, R[cntr].x1);
}
else if (df && uf) {
type[cnt + 1] = 3, lb[cnt + 1] = l[i], rb[cnt + 1] = r[i];
D[++ cntd] = Line{l[i], r[i], cnt + 1, cnt + 2}, cnt += 2;
type[cnt + 1] = 4, lb[cnt + 1] = l[i], rb[cnt + 1] = r[i];
U[++ cntu] = Line{l[i], r[i], cnt + 1, cnt + 2}, cnt += 2;
TwoSAT::AddEdge(D[cntd].x2, U[cntu].x1);
TwoSAT::AddEdge(U[cntu].x2, D[cntd].x1);
}
}
TwoSAT::n = cnt;
std::sort(L + 1, L + cntl + 1);
std::sort(R + 1, R + cntr + 1);
std::sort(D + 1, D + cntd + 1);
std::sort(U + 1, U + cntu + 1);
for (int i = 1; i <= cntl; ++ i) {
int j = std::lower_bound(L + 1, L + i + 1, L[i].l) - L - 1;
if (j) TwoSAT::AddEdge(L[i].x1, prel1[j]), TwoSAT::AddEdge(prel2[j], L[i].x2);
prel1[i] = ++ cnt, prel2[i] = ++ cnt;
TwoSAT::AddEdge(prel1[i], L[i].x2), TwoSAT::AddEdge(L[i].x1, prel2[i]);
if (i > 1) TwoSAT::AddEdge(prel1[i], prel1[i - 1]), TwoSAT::AddEdge(prel2[i - 1], prel2[i]);
}
for (int i = 1; i <= cntr; ++ i) {
int j = std::lower_bound(R + 1, R + i + 1, R[i].l) - R - 1;
if (j) TwoSAT::AddEdge(R[i].x1, prer1[j]), TwoSAT::AddEdge(prer2[j], R[i].x2);
prer1[i] = ++ cnt, prer2[i] = ++ cnt;
TwoSAT::AddEdge(prer1[i], R[i].x2), TwoSAT::AddEdge(R[i].x1, prer2[i]);
if (i > 1) TwoSAT::AddEdge(prer1[i], prer1[i - 1]), TwoSAT::AddEdge(prer2[i - 1], prer2[i]);
}
for (int i = 1; i <= cntd; ++ i) {
int j = std::lower_bound(D + 1, D + i + 1, D[i].l) - D - 1;
if (j) TwoSAT::AddEdge(D[i].x1, pred1[j]), TwoSAT::AddEdge(pred2[j], D[i].x2);
pred1[i] = ++ cnt, pred2[i] = ++ cnt;
TwoSAT::AddEdge(pred1[i], D[i].x2), TwoSAT::AddEdge(D[i].x1, pred2[i]);
if (i > 1) TwoSAT::AddEdge(pred1[i], pred1[i - 1]), TwoSAT::AddEdge(pred2[i - 1], pred2[i]);
}
for (int i = 1; i <= cntu; ++ i) {
int j = std::lower_bound(U + 1, U + i + 1, U[i].l) - U - 1;
if (j) TwoSAT::AddEdge(U[i].x1, preu1[j]), TwoSAT::AddEdge(preu2[j], U[i].x2);
preu1[i] = ++ cnt, preu2[i] = ++ cnt;
TwoSAT::AddEdge(preu1[i], U[i].x2), TwoSAT::AddEdge(U[i].x1, preu2[i]);
if (i > 1) TwoSAT::AddEdge(preu1[i], preu1[i - 1]), TwoSAT::AddEdge(preu2[i - 1], preu2[i]);
}
ans = TwoSAT::solve();
int leftup = up, leftdown = down, rightup = up, rightdown = down;
int upleft = left, upright = right, downleft = left, downright = right;
for (int i : ans)
if (type[i] == 1) leftup = min(leftup, rb[i]), leftdown = max(leftdown, lb[i]);
else if (type[i] == 2) rightup = min(rightup, rb[i]), rightdown = max(rightdown, lb[i]);
else if (type[i] == 3) downright = min(downright, rb[i]), downleft = max(downleft, lb[i]);
else if (type[i] == 4) upright = min(upright, rb[i]), upleft = max(upleft, lb[i]);
printf("%d %d\n%d %d\n%d %d\n%d %d", left, leftup, right, rightup, downleft, down, upleft, up);
return 0;
}
本文作者:zqs2020
本文链接:https://www.cnblogs.com/stinger/p/16049184.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步