AT_arc069_d [ARC069F] Flags 题解
考虑二分答案。
每个点要么选 ,要么选 ,这本质上是一个 2-SAT 模型。
直接建边的话,枚举 ,并且判断 时,若 取 ,那么 取 。其余的 同理,复杂度 。
考虑优化,发现如果按 排序,对于一个 ,连到的 是一个区间的,可以直接用线段树或分块优化建图。
由于数据范围很小,,所以我选择写了好写的分块优化建图,大概是对于每一块建一个虚点向块内所有点连边。 向 连边时整块直接连向虚点,散块暴力。结合二分,总复杂度 。
启示:直接连边很慢时,考虑一些性质,例如连的是一段区间或前后缀时,可以优化建图。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
vector<int> G[N];
int dfn[N], low[N], idx, cnt, id[N];
bool in_stk[N];
int stk[N], top;
int n, m;
int len;
int cc;
struct Node
{
int a, b, id;
Node(int _a, int _b, int _i): a(_a), b(_b), id(_i){}
Node() = default;
}p[N];
inline int get(int x)
{
return x / len;
}
inline int L(int x)
{
return max(1, x * len);
}
int idp[N];
void add(int u, int l, int r)
{
if (l > r) return;
if (r - l <= len + 5)
{
for (int i = l; i <= r; i++)
{
G[u].emplace_back(p[i].id + n);
}
return;
}
int L = get(l) + 1, R = get(r) - 1;
for (int i = L; i <= R; i++)
{
G[u].emplace_back(idp[i]);
}
for (; get(l) != L; l++) G[u].emplace_back(p[l].id + n);
for (; get(r) != R; r--) G[u].emplace_back(p[r].id + n);
}
void add2(int u, int l, int r)
{
if (l > r) return;
if (r - l <= len + 5)
{
for (int i = l; i <= r; i++)
{
//cout << "Edge: ";
G[u].emplace_back(p[i].id);
}
return;
}
int L = get(l) + 1, R = get(r) - 1;
for (int i = L; i <= R; i++)
{
G[u].emplace_back(idp[i]);
}
for (; get(l) != L; l++) G[u].emplace_back(p[l].id);
for (; get(r) != R; r--) G[u].emplace_back(p[r].id);
}
void tarjan(int u)
{
dfn[u] = low[u] = ++idx;
stk[++top] = u;
in_stk[u] = 1;
for (auto &j : G[u])
{
if (!dfn[j])
{
tarjan(j);
low[u] = min(low[u], low[j]);
}
else if (in_stk[j]) low[u] = min(low[u], dfn[j]);
}
if (dfn[u] == low[u])
{
cnt++;
int y = 0;
do
{
y = stk[top--];
in_stk[y] = 0;
id[y] = cnt;
} while (y != u);
}
}
inline bool check(int x)
{
sort(p + 1, p + n + 1, [&](const Node& x, const Node& y){return x.a < y.a;});
sort(p + n + 1, p + n + n + 1, [&](const Node& x, const Node& y){return x.b < y.b;});
for (int i = 1; i <= cc; i++)
{
G[i].clear(), dfn[i] = low[i] = id[i] = in_stk[i] = 0;
}
cc = 2 * n;
top = 0;
for (int i = get(1); i <= get(n); i++)
{
idp[i] = ++cc;
int l = L(i), r = min(n, L(i + 1) - 1);
for (int j = l; j <= r; j++)
{
G[cc].emplace_back(p[j].id + n);
//cout << "Edge: " << cc << " " << p[j].id + n << "\n";
}
}
for (int i = 1; i <= n; i++)
{
int l = p[i].a - x + 1, r = p[i].a + x - 1;
int ll = lower_bound(p + 1, p + n + 1, Node(l, 0, 0), [&](const Node& x, const Node& y){return x.a < y.a;}) - p;
int rr = upper_bound(p + 1, p + n + 1, Node(r, 0, 0), [&](const Node& x, const Node& y){return x.a < y.a;}) - p - 1;
if (ll >= 1 && ll <= n && rr >= 1 && rr <= n && rr >= ll)
{
add(p[i].id, ll, i - 1);
add(p[i].id, i + 1, rr);
}
}
for (int i = 1; i <= n; i++)
{
int l = p[i].b - x + 1, r = p[i].b + x - 1;
int ll = lower_bound(p + 1, p + n + 1, Node(l, 0, 0), [&](const Node& x, const Node& y){return x.a < y.a;}) - p;
int rr = upper_bound(p + 1, p + n + 1, Node(r, 0, 0), [&](const Node& x, const Node& y){return x.a < y.a;}) - p - 1;
if (ll >= 1 && ll <= n && rr >= 1 && rr <= n && rr >= ll)
{//cout << "djb: " << i << " " << ll << " " << rr << "\n";
if (i >= ll && i <= rr)
{
add(p[i].id + n, ll, i - 1);
add(p[i].id + n, i + 1, rr);
}
else add(p[i].id + n, ll, rr);
}
}
//
for (int i = get(0); i <= get(2 * n); i++)
{
idp[i] = ++cc;
int l = L(i), r = min(2 * n, L(i + 1) - 1);
for (int j = l; j <= r; j++)
{
//cout << "Edge: " << cc << " " << p[j].id << "\n";
G[cc].emplace_back(p[j].id);
}
}
for (int i = n + 1; i <= 2 * n; i++)
{
int l = p[i].a - x + 1, r = p[i].a + x - 1;
int ll = lower_bound(p + n + 1, p + 2 * n + 1, Node(0, l, 0), [&](const Node& x, const Node& y){return x.b < y.b;}) - p;
int rr = upper_bound(p + n + 1, p + 2 * n + 1, Node(0, r, 0), [&](const Node& x, const Node& y){return x.b < y.b;}) - p - 1;
if (ll >= n && ll <= 2 * n && rr >= n && rr <= 2 * n && rr >= ll)
{
if (i >= ll && i <= rr)
{
add2(p[i].id, ll, i - 1);
add2(p[i].id, i + 1, rr);
}
else add2(p[i].id, ll, rr);
}
}
for (int i = n + 1; i <= 2 * n; i++)
{
int l = p[i].b - x + 1, r = p[i].b + x - 1;
int ll = lower_bound(p + n + 1, p + 2 * n + 1, Node(0, l, 0), [&](const Node& x, const Node& y){return x.b < y.b;}) - p;
int rr = upper_bound(p + n + 1, p + 2 * n + 1, Node(0, r, 0), [&](const Node& x, const Node& y){return x.b < y.b;}) - p - 1;
if (ll >= n && ll <= 2 * n && rr >= n && rr <= 2 * n && rr >= ll)
{
add2(p[i].id + n, ll, i - 1);
add2(p[i].id + n, i + 1, rr);
}
}
for (int i = 1; i <= cc; i++) if (!dfn[i]) tarjan(i);
for (int i = 1; i <= n; i++)
{
if (id[i] == id[i + n]) return 0;
}
return 1;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
len = sqrt(n);
for (int i = 1; i <= n; i++)
{
cin >> p[i].a >> p[i].b, p[i].id = i;
}
for (int i = 1; i <= n; i++) p[i + n] = p[i];
int l = 0, r = (int)1e9, ans = 0;
while (l <= r)
{
int mid = l + r >> 1;
if (check(mid)) ans = mid, l = mid + 1;
else r = mid - 1;
}
cout << ans << "\n";
return 0;
}

浙公网安备 33010602011771号