题解:P12031 [USACO25OPEN] Forklift Certified P
沉石鱼惊旋
·
·
题解
做法
一个简单的发现是,我们每个箱子只需要关心『右上角』下方的区域是否包含某个箱子的『左下角』。
但是删除箱子需要支持删掉某个 $x$ 的某个 $y$ 。而删掉之后新的 $y'$ 可能成为这一行的最小值,我们对线段树的叶子结点开 `std::set` 维护一下。
感谢 @[hard_plan](https://www.luogu.com.cn/user/749406) 指出,这里元素坐标都是不一样的(我一开始没看到这个信息,难过),叶子结点只需要记录对应值就可以了。
$M=1$ 考虑类似拓扑排序的做法。但是按枚举一个点然后枚举出边的做法肯定不行。我们考虑尝试删除 $u$ 的时候,找到一个挡住他的 $v$,尝试递归下去删掉 $v$。如果删掉 $v$ 之后没有障碍了就结束了,否则继续找到下一个 $v_2$ 去删掉,直到 $u$ 可以被删除。重复这个过程。显然每个点只会被删除一次。其实就是一个拓扑排序的 DFS 写法。
注意可能会出自环。先把 $u$ 点删掉就可以了。
# 代码
<https://www.luogu.com.cn/record/212388266>
```cpp
#include <bits/stdc++.h>
using namespace std;
#define getchar() p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++
char buf[1000000], *p1 = buf, *p2 = buf;
template <typename T>
void read(T &x)
{
x = 0;
int f = 1;
char c = getchar();
for (; c < '0' || c > '9'; c = getchar())
if (c == '-')
f = -f;
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
x *= f;
}
template <typename T, typename... Args>
void read(T &x, Args &...y)
{
read(x);
read(y...);
}
template <class T>
void write(T x)
{
static int stk[30];
if (x < 0)
putchar('-'), x = -x;
int top = 0;
do
{
stk[top++] = x % 10, x /= 10;
} while (x);
while (top)
putchar(stk[--top] + '0');
}
template <class T>
void write(T x, char lastChar) { write(x), putchar(lastChar); }
const int inf = 1e9;
int N, M;
int n;
struct point
{
int x, y;
};
point a[100020];
point b[100020];
array<int, 2> s[200020];
struct SegTree
{
struct node
{
array<int, 2> mn;
} t[200020 << 2];
#define ls id << 1
#define rs id << 1 | 1
#define Llen (mid - l + 1)
#define Rlen (r - mid)
void push_up(int id) { t[id].mn = min(t[ls].mn, t[rs].mn); }
void build(int id = 1, int l = 1, int r = N)
{
if (l == r)
return t[id].mn = {inf, -1}, void();
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
push_up(id);
}
void add(int pos, array<int, 2> v, int k, int id = 1, int l = 1, int r = N)
{
if (r < pos || l > pos)
return;
if (pos <= l && r <= pos)
{
if (k > 0)
s[pos] = v;
else
s[pos] = {0, 0};
t[id].mn = s[pos] == (array<int, 2>){0, 0} ? (array<int, 2>){inf, -1} : s[pos];
return;
}
int mid = l + r >> 1;
add(pos, v, k, ls, l, mid);
add(pos, v, k, rs, mid + 1, r);
push_up(id);
}
array<int, 2> query(int ql, int qr, int id = 1, int l = 1, int r = N)
{
if (r < ql || l > qr)
return {inf, -1};
if (ql <= l && r <= qr)
return t[id].mn;
int mid = l + r >> 1;
return min(query(ql, qr, ls, l, mid), query(ql, qr, rs, mid + 1, r));
}
} T;
namespace M1
{
bool vis[100020];
bool del[100020];
void dfs(int u)
{
if (del[u])
return;
if (!vis[u])
T.add(a[u].x, {a[u].y, u}, -1), vis[u] = 1;
auto [w, v] = T.query(1, b[u].x);
if (w >= b[u].y)
return del[u] = 1, write(u, ' ');
dfs(v);
dfs(u);
}
void solve()
{
read(n);
N = n << 1;
memset(vis, 0, sizeof(bool) * (n + 5));
memset(del, 0, sizeof(bool) * (n + 5));
T.build();
for (int i = 1; i <= n; i++)
read(a[i].x, a[i].y, b[i].x, b[i].y);
for (int i = 1; i <= n; i++)
T.add(a[i].x, {a[i].y, i}, 1);
for (int i = 1; i <= n; i++)
dfs(i);
putchar('\n');
}
};
namespace M2
{
void solve()
{
read(n);
N = n << 1;
T.build();
for (int i = 1; i <= n; i++)
read(a[i].x, a[i].y, b[i].x, b[i].y);
for (int i = 1; i <= n; i++)
T.add(a[i].x, {a[i].y, i}, 1);
for (int i = 1; i <= n; i++)
T.add(a[i].x, {a[i].y, i}, -1), write(T.query(1, b[i].x)[0] >= b[i].y);
putchar('\n');
}
}
int main()
{
int t;
read(t, M);
while (t--)
(M & 1 ? M1::solve() : M2::solve());
return 0;
}
```