P5987 [PA2019] Terytoria 题解

两维独立,问题变为给一堆线段,每个线段可以选中间或两边,求选出的东西之交最大是多少。

按端点把数轴分段,则钦定任意一段在最终的交中,就可以确定所有线段的选择方案。

定义 f(i) 表示钦定 i 段在最终的交中时交的大小,则答案为 maxf(i)

考虑从左往右依次钦定每段在最终的交中,则所有线段初始都选两边,

钦定到一条线段内部时这条线段切换为选中间,再次钦定到一条线段外部时这条线段切换为选两边。

Sol 1

考虑扫描时,线段树维护当前选择方案下,每段被覆盖多少次。

则切换选择方案相当于区间加减,当前 f(i)n 的个数。

#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

考虑哈希当前选择方案,对每条线段随机赋权,线段 i 的权值 vi{aii 在当前方案中选中间bii 在当前方案中选两边,其中 ai,bi 随机生成,

则钦定 i 段必选时,选择方案的哈希值 hivj,于是 f(i) 即为哈希值与其相同的段的长度之和。

%: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;
}
posted @   Jijidawang  阅读(6)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示