H-Hopping Rabbit(2021牛客暑期多校训练营6)【扫描线】

H-Hopping Rabbit

思路

其实从 ( x , y ) (x, y) (x,y) 点出发和从 ( x + d , y + d ) (x + d, y + d) (x+d,y+d) 出发是一样的,因为左右都只能跳 d d d 的距离,那么有区别的出发点其实都可以归纳到 x ∈ [ 0 , d ) , y ∈ [ 0 , d ) x \in [0, d), y \in [0, d) x[0,d),y[0,d) 的范围内。我们把所有的陷阱都通过这种方法映射到 x ∈ [ 0 , d ) , y ∈ [ 0 , d ) x \in [0, d), y \in [0, d) x[0,d),y[0,d) 的范围内(赋值为1),然后找任意一个值为0的点输出其坐标即可,若没有这样的点就是不可行。

听起来很简单,但是d的范围1e5,暴力显然不行。开始觉得用二维线段树也可以做,奈何不会,后来在想“什么数据结构可以用来处理矩形覆盖问题”的时候,突然想到扫描线。扫描线扫的过程中查找是不是有某一列的值不是满的,若有就说明该列有0,若无则没有答案。若找到了某个有0的列,就将其之前的所有线段开头结尾在一个初始为0的数组中标记(开头+1,结尾-1),最后 O ( n ) O(n) O(n) 求一遍前缀和就可以知道在修改到该列时,整列的状态,此时若有前缀和为0的位置,就是我们要找的答案。这样的复杂度是 O ( log ⁡ d + d ) O(\log d + d) O(logd+d)​ ,是可以通过的。

不过好像题目数据有点弱,我们漏判了开头到第一个矩形的部分,居然过了。

代码

赛后自己重新写了一遍,完美复现了赛场上的所有错误(不是)

被负数取模坑了几个小时,好像这个细节还是我在赛场上提出来的,转头就忘不愧是我()

容易出错的地方:输入的坐标可能是负数,要处理成正数再取模;离散化处理y轴坐标时,如果是矩阵在 [ 0 , d ) [0, d) [0,d)​ 中的映射不连续(即取模后 x 1 > x 2   o r   y 1 > y 2 x_1 > x_2 \ or \ y_1 > y_2 x1>x2 or y1>y2​ 的情况),要记得多添加0和d两个y轴坐标。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;

int n;
struct Segment
{
    ll x, y1, y2;
    int k;
    bool operator < (const Segment& t) const
    {
        return x < t.x;
    }
} seg[N * 8];

struct node
{
    int l, r;
    ll cnt;
    ll len;
} tr[N * 16];

vector<int> ys;

int find(int y)
{
    return lower_bound(ys.begin(), ys.end(), y) - ys.begin();
}

void pushup(int u)
{
    if(tr[u].cnt)
        tr[u].len = ys[tr[u].r + 1] - ys[tr[u].l];
    else if(tr[u].l != tr[u].r)
        tr[u].len = tr[u << 1].len + tr[u << 1 | 1].len;
    else
        tr[u].len = 0;
}

void build(int u, int l, int r)
{
    tr[u] = {l, r, 0, 0};
    if(l != r)
    {
        int mid = (l + r) >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
    }
}

void modify(int u, int l, int r, int k)
{
    if(tr[u].l >= l && tr[u].r <= r)
    {
        tr[u].cnt += k;
        pushup(u);
    }
    else
    {
        int mid = (tr[u].l + tr[u].r) >> 1;
        if(l <= mid)
            modify(u << 1, l, r, k);
        if(r > mid)
            modify(u << 1 | 1, l, r, k);
        pushup(u);
    }
}

int f[N];

int main()
{
    int n, d, j = 0;
    scanf("%d%d", &n, &d);
    bool flag = 0;
    seg[j++] = {0, 0, d, 0};
    seg[j++] = {d, 0, d, 0};
    ll add = 1e9 * d;
    for(int i = 0; i < n; i++)
    {
        ll x1, y1, x2, y2;
        scanf("%lld%lld%lld%lld", &x1, &y1, &x2, &y2);
        if(x2 - x1 >= d && y2 - y1 >= d)
        {
            flag = 1;
            break;
        }
        x1 += add;
        x2 += add;
        y1 += add;
        y2 += add;

        x1 %= d;
        y1 %= d;
        x2 = (x2 - 1 + d) % d + 1;
        y2 = (y2 - 1 + d) % d + 1;
        if(x1 < x2)
        {
            if(y1 < y2)
            {
                seg[j++] = {x1, y1, y2, 1};
                seg[j++] = {x2, y1, y2, -1};
                ys.push_back(y1);
                ys.push_back(y2);
            }
            else if(y1 > y2) // [y1, d) + [0, y2)
            {
                seg[j++] = {x1, y1, d, 1};
                seg[j++] = {x2, y1, d, -1};
                seg[j++] = {x1, 0, y2, 1};
                seg[j++] = {x2, 0, y2, -1};
                ys.push_back(y1);
                ys.push_back(y2);
                ys.push_back(0);
                ys.push_back(d);
            }
            else
            {
                seg[j++] = {x1, 0, d, 1};
                seg[j++] = {x2, 0, d, -1};
                ys.push_back(0);
                ys.push_back(d);
            }
        }
        else if(x1 > x2)
        {
            if(y1 < y2) // [x1, d) + [0, x2)
            {
                seg[j++] = {x1, y1, y2, 1};
                seg[j++] = {d, y1, y2, -1};
                seg[j++] = {0, y1, y2, 1};
                seg[j++] = {x2, y1, y2, -1};
                ys.push_back(y1);
                ys.push_back(y2);
            }
            else if(y1 > y2) // [x1, d) + [0, x2) + [y1, d) + [0, y2)
            {
                seg[j++] = {x1, y1, d, 1};
                seg[j++] = {d, y1, d, -1};
                seg[j++] = {0, y1, d, 1};
                seg[j++] = {x2, y1, d, -1};
                seg[j++] = {x1, 0, y2, 1};
                seg[j++] = {d, 0, y2, -1};
                seg[j++] = {0, 0, y2, 1};
                seg[j++] = {x2, 0, y2, -1};
                ys.push_back(y1);
                ys.push_back(y2);
                ys.push_back(0);
                ys.push_back(d);
            }
            else
            {
                seg[j++] = {x1, 0, d, 1};
                seg[j++] = {d, 0, d, -1};
                seg[j++] = {0, 0, d, 1};
                seg[j++] = {x2, 0, d, -1};
                ys.push_back(0);
                ys.push_back(d);
            }
        }
        else
        {
            if(y1 < y2)
            {
                seg[j++] = {0, y1, y2, 1};
                seg[j++] = {d, y1, y2, -1};
                ys.push_back(y1);
                ys.push_back(y2);
            }
            else if(y1 > y2) // [y1, d) + [0, y2)
            {
                seg[j++] = {0, y1, d, 1};
                seg[j++] = {d, y1, d, -1};
                seg[j++] = {0, 0, y2, 1};
                seg[j++] = {d, 0, y2, -1};
                ys.push_back(y1);
                ys.push_back(y2);
                ys.push_back(0);
                ys.push_back(d);
            }
            else
            {
                flag = 1;
                break;
            }
        }
    }

    if(flag)
    {
        printf("NO\n");
        return 0;
    }

    int cnt = j;
    sort(seg, seg + cnt);
    sort(ys.begin(), ys.end());
    ys.erase(unique(ys.begin(), ys.end()), ys.end());

    build(1, 0, ys.size() - 2);

    int res = 0;

    int pos = -1;

    for(int i = 0; i < cnt; i++)
    {
        if(i > 0)
        {
            int h = seg[i].x - seg[i - 1].x;
            int w = tr[1].len;
            if(h && w < d)
            {
                pos = i;
                break;
            }
            if(seg[i].k)
                modify(1, find(seg[i].y1), find(seg[i].y2) - 1, seg[i].k);
        }
    }
    if(pos == -1)
    {
        printf("NO\n");
        return 0;
    }
    for(int i = 0; i < pos; i++)
    {
        f[seg[i].y1] += seg[i].k;
        f[seg[i].y2] -= seg[i].k;
    }
    int y = -1;
    for(int i = 0; i < d; i++)
    {
        if(i > 0)
            f[i] = f[i - 1] + f[i];
        if(f[i] == 0)
        {
            y = i;
            break;
        }
    }
    if(y == -1)
    {
        printf("NO\n");
        return 0;
    }
    int x = seg[pos - 1].x;
    printf("YES\n%d %d\n", x, y);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值