P5987 [PA2019] Terytoria 题解
两维独立,问题变为给一堆线段,每个线段可以选中间或两边,求选出的东西之交最大是多少。
按端点把数轴分段,则钦定任意一段在最终的交中,就可以确定所有线段的选择方案。
定义
考虑从左往右依次钦定每段在最终的交中,则所有线段初始都选两边,
钦定到一条线段内部时这条线段切换为选中间,再次钦定到一条线段外部时这条线段切换为选两边。
Sol 1
考虑扫描时,线段树维护当前选择方案下,每段被覆盖多少次。
则切换选择方案相当于区间加减,当前
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
int n, X, Y, l1[500050], r1[500050], l2[500050], r2[500050];
inline int R()
{
int q = 0;
char c = getchar();
while (c < '0' || c > '9')
c = getchar();
while (c >= '0' && c <= '9')
q = q * 10 + c - '0', c = getchar();
return q;
}
struct S
{
struct T
{
int v, w, z;
T() : v(0), w(0), z(0) {}
} R[1000050 << 2];
struct E
{
int v, w, t;
} e[1000050];
int c, h[1000050], b[1000050];
inline void A(int u, int v, int w)
{
e[++c] = {v, w, h[u]};
h[u] = c;
}
inline void u(int p)
{
if (R[p << 1].v == R[p << 1 | 1].v)
R[p].v = R[p << 1].v, R[p].w = R[p << 1].w + R[p << 1 | 1].w;
if (R[p << 1].v > R[p << 1 | 1].v)
R[p].v = R[p << 1].v, R[p].w = R[p << 1].w;
if (R[p << 1].v < R[p << 1 | 1].v)
R[p].v = R[p << 1 | 1].v, R[p].w = R[p << 1 | 1].w;
}
inline void f(int p, int x)
{
R[p].v += x;
R[p].z += x;
}
inline void d(int p)
{
if (R[p].z)
f(p << 1, R[p].z), f(p << 1 | 1, R[p].z), R[p].z = 0;
}
void B(int s, int t, int p)
{
if (s == t)
{
R[p].w = b[s + 1] - b[s];
return;
}
int m = s + t >> 1;
B(s, m, p << 1);
B(m + 1, t, p << 1 | 1);
u(p);
}
void M(int l, int r, int x, int s, int t, int p)
{
if (l <= s && t <= r)
return f(p, x);
d(p);
int m = s + t >> 1;
if (l <= m)
M(l, r, x, s, m, p << 1);
if (r > m)
M(l, r, x, m + 1, t, p << 1 | 1);
u(p);
}
int Q(int *l, int *r, int X)
{
memset(R, 0, sizeof R);
memset(b, 0, sizeof b);
int m = 0, q = 0;
c = 0;
for (int i = 1; i<= 1e6; ++i)
h[i] = 0;
b[++m] = 0;
b[++m] = X;
for (int i = 1; i <= n; ++i)
b[++m] = l[i], b[++m] = r[i];
sort(b + 1, b + m + 1);
m = unique(b + 1, b + m + 1) - b - 1;
for (int i = 1; i <= n; ++i)
{
A(l[i] = lower_bound(b + 1, b + m + 1, l[i]) - b, i, 1);
A(r[i] = lower_bound(b + 1, b + m + 1, r[i]) - b, i, 2);
}
B(1, m - 1, 1);
for (int i = 1; i <= n; ++i)
{
if (l[i] != 1)
M(1, l[i] - 1, 1, 1, m - 1, 1);
if (r[i] != m)
M(r[i], m - 1, 1, 1, m - 1, 1);
}
for (int i = 1; i < m; ++i)
{
for (int v = h[i]; v; v = e[v].t)
{
int j = e[v].v;
if (e[v].w == 1)
{
if (l[j] != 1)
M(1, l[j] - 1, -1, 1, m - 1, 1);
if (r[j] != m)
M(r[j], m - 1, -1, 1, m - 1, 1);
if (l[j] != r[j])
M(l[j], r[j] - 1, 1, 1, m - 1, 1);
}
else
{
if (l[j] != r[j])
M(l[j], r[j] - 1, -1, 1, m - 1, 1);
if (l[j] != 1)
M(1, l[j] - 1, 1, 1, m - 1, 1);
if (r[j] != m)
M(r[j], m - 1, 1, 1, m - 1, 1);
}
}
q = max(q, R[1].w);
}
return q;
}
} SA, SB;
signed main()
{
// freopen("globe.in", "r", stdin);
// freopen("globe.out", "w", stdout);
n = R();
X = R();
Y = R();
for (int i = 1; i <= n; ++i)
{
l1[i] = R(), l2[i] = R(), r1[i] = R(), r2[i] = R();
if (l1[i] > r1[i])
swap(l1[i], r1[i]);
if (l2[i] > r2[i])
swap(l2[i], r2[i]);
}
printf("%lld", 1ll * SA.Q(l1, r1, X) * SA.Q(l2, r2, Y));
return 0;
}
Sol 2
考虑哈希当前选择方案,对每条线段随机赋权,线段
则钦定
%:include <cstdio>
%:include <cstring>
%:include <vector>
%:include <algorithm>
%:include <unordered_map>
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
using namespace std;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
int n, X, Y, l1[500050], r1[500050], l2[500050], r2[500050];
inline int R()
{
int q = 0;
char c = getchar();
while (c < '0' || c > '9')
c = getchar();
while (c >= '0' && c <= '9')
q = q * 10 + c - '0', c = getchar();
return q;
}
struct S
{
struct Z
{
int x, y;
bool operator<(Z b) const { return x < b.x; }
};
int c, b[1000050], U[1000050], V[1000050];
Z P[1000050];
int Q(int *l, int *r, int X)
{
unordered_map<unsigned long long, int> C;
int m = 0, q = 0;
unsigned long long Z = 0;
b[++m] = 0;
b[++m] = X;
for (int i = 1; i <= n; ++i)
b[++m] = l[i], b[++m] = r[i], U[i] = rand(), V[i] = rand();
sort(b + 1, b + m + 1);
m = unique(b + 1, b + m + 1) - b - 1;
c = 0;
for (int i = 1; i <= n; ++i)
{
P[++c] = {l[i] = lower_bound(b + 1, b + m + 1, l[i]) - b, i};
P[++c] = {r[i] = lower_bound(b + 1, b + m + 1, r[i]) - b, -i};
}
sort(P + 1, P + c + 1);
for (int i = 1; i <= n; ++i)
Z += U[i];
for (int i = 1, p = 0; i < m; ++i)
{
while (p < c && P[p + 1].x <= i)
{
++p;
if (P[p].y > 0)
Z = Z - U[P[p].y] + V[P[p].y];
else
Z = Z - V[-P[p].y] + U[-P[p].y];
}
q = max(q, C[Z] += b[i + 1] - b[i]);
}
return q;
}
} SA;
signed main()
{
// freopen("globe.in", "r", stdin);
// freopen("globe.out", "w", stdout);
srand(388651);
n = R();
X = R();
Y = R();
for (int i = 1; i <= n; ++i)
l1[i] = R(), l2[i] = R(), r1[i] = R(), r2[i] = R();
printf("%lld", 1ll * SA.Q(l1, r1, X) * SA.Q(l2, r2, Y));
return 0;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具