AT_joisc2017_j 誘拐 2 (Abduction 2) 题解

对于一个矩形,已知其四边上不考虑其内部道路的所有答案,考虑其中车流指数最大的道路。

如图,红线为矩形中车流指数最大的道路,

两端点 (k,s),(k,t) 不考虑矩形中内部道路的答案分别为 x,y

i[s,t],可以确定 (k,i) 的答案为 max{x+is,y+ti}

若所询问的点在红线上,则可以返回答案,否则向所询问的点所在的子矩形递归。

设所询问的点在上半个子矩形中。

如图,蓝线为子矩形中车流指数最大的道路,

端点 (s,k) 在黑线上,已知不考虑子矩形中内部道路的答案,

端点 (t,k) 在红线上,不考虑子矩形中内部道路的答案为 max{x+ts,y+tt}

若所询问的点在蓝线上,则可以返回答案,否则向所询问的点所在的子矩形递归。

特别地,最初整个矩形四边上不考虑其内部道路的所有答案为 0

而且题目中有:

移动开始时,可以任意选择方向。

所以需要考虑开始时的移动方向,递归终止时如果不满足此时枚举的方向需要继续递归。

用 ST 表维护子矩形中车流指数最大的道路。

容易发现最坏情况下最多递归 H+W 层,所以复杂度为 O(Q(H+W))

#include <cstdio>
#include <algorithm>
using namespace std;
struct S
{
    int s, t;
    long long x, y;
    bool v;
} a[50050], b[50050];
int n, m, q, x, y;
long long s;
struct T
{
    int n;
    pair<int, int> a[20][50050];
    void B(int _)
    {
        n = _;
        for (int i = 1; i <= n; ++i)
            scanf("%d", &a[0][i].first), a[0][i].second = i;
        for (int i = 1; 1 << i <= n; ++i)
            for (int j = 1; j + (1 << i) - 1 <= n; ++j)
                a[i][j] = max(a[i - 1][j], a[i - 1][j + (1 << i - 1)]);
    }
    pair<int, int> Q(int x, int y)
    {
        if (x > y)
            return {0, 0};
        int k = __lg(y - x + 1);
        return max(a[k][x], a[k][y - (1 << k) + 1]);
    }
} X, Y;
long long D(int s1, int s2, int t1, int t2, int k1, int k2, int f, int g)
{
    auto P = X.Q(s1 + (f >> 0 & 1), t1 - (f >> 1 & 1)),
         Q = Y.Q(s2 + (f >> 2 & 1), t2 - (f >> 3 & 1));
    int x = P.second, y = Q.second;
    if (P > Q)
    {
        a[x] =
            {s2, t2,
             b[s2].v ? max(b[s2].x + x - b[s2].s, b[s2].y + b[s2].t - x) : 0,
             b[t2].v ? max(b[t2].x + x - b[t2].s, b[t2].y + b[t2].t - x) : 0,
             1};
        if (k1 == x)
        {
            if (g == 0)
                return D(s1, s2, x, t2, k1, k2, f | 2, g);
            if (g == 1)
                return D(x, s2, t1, t2, k1, k2, f | 1, g);
            if (g == 2)
                return a[x].x + k2 - s2;
            if (g == 3)
                return a[x].y + t2 - k2;
        }
        if (k1 > x)
            return D(x, s2, t1, t2, k1, k2, f | 1, g);
        if (k1 < x)
            return D(s1, s2, x, t2, k1, k2, f | 2, g);
    }
    if (P < Q)
    {
        b[y] =
            {s1, t1,
             a[s1].v ? max(a[s1].x + y - a[s1].s, a[s1].y + a[s1].t - y) : 0,
             a[t1].v ? max(a[t1].x + y - a[t1].s, a[t1].y + a[t1].t - y) : 0,
             1};
        if (k2 == y)
        {
            if (g == 0)
                return b[y].x + k1 - s1;
            if (g == 1)
                return b[y].y + t1 - k1;
            if (g == 2)
                return D(s1, s2, t1, y, k1, k2, f | 8, g);
            if (g == 3)
                return D(s1, y, t1, t2, k1, k2, f | 4, g);
        }
        if (k2 > y)
            return D(s1, y, t1, t2, k1, k2, f | 4, g);
        if (k2 < y)
            return D(s1, s2, t1, y, k1, k2, f | 8, g);
    }
}
void F(int x, int y, int g)
{
    for (int i = 1; i <= n; ++i)
        a[i].v = 0;
    for (int i = 1; i <= m; ++i)
        b[i].v = 0;
    s = max(s, D(1, 1, n, m, x, y, 0, g));
}
signed main()
{
    scanf("%d%d%d", &n, &m, &q);
    X.B(n);
    Y.B(m);
    while (q--)
    {
        scanf("%d%d", &x, &y);
        s = 0;
        if (x != 1)
            F(x, y, 0);
        if (x != n)
            F(x, y, 1);
        if (y != 1)
            F(x, y, 2);
        if (y != m)
            F(x, y, 3);
        printf("%lld\n", s);
    }
    return 0;
}
posted @   Jijidawang  阅读(13)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示