JZOJ5049 [GDOI2017模拟一试4.11] 腐女的生日

pty为庆祝腐女生日,委托djy穿越校园送礼,避开教学楼找到最短路径。采用线段树与扫描线算法,解决djy从起点到终点的最短步数问题,确保不触及任何障碍。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

腐女要过生日了,pty 想给腐女送礼物,但是腐女所在的教室离pty 的教室太远了,于是pty就拜托会动归和A星的djy帮忙送礼物。djy在学校建立了一个平面直角坐标系,他站在了(0,0)点,腐女在(x0,y0)点,djy每次只能往上下左右四个方向移动一步,中间有n栋矩形教学楼,每个教学楼给出两个对角的坐标,并且保证每栋教学楼的周围区域(如图所示)不会有别的教学楼,即djy可以绕一个教学楼走不会碰到任何障碍,现在djy 想知道从起点到终点不碰到任何教学楼,最短需要多少步。
在这里插入图片描述
Data Constraint
保证所有的y坐标在[-106,106]
所有的x坐标在[0,10^6]
70%的数据保证:n<=1000
100%的数据保证:n<=10^5
Solution
发现其实并不需要向左走,用线段树+扫描线,线段树表示到yi的最小步数,每次扫到矩阵右边界时,分别用从上往下走或从下往上走来更新。
Code

#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <algorithm>

#define il inline
#define Int register int
#define max(x, y) (x > y) ? (x) : (y)
#define min(x, y) (x < y) ? (x) : (y)

using namespace std; 

const int maxn1 = 2e5 + 7, maxn = 1e6 + 1;
struct code
{
    int x,y,yy,z;
}a[maxn1];
struct code1
{
    int bz,sum,bz1;
}f[maxn * 10];
int n, i, t, j, k, l, sx, sy, x, y, z, ans, bz;

il bool cmp(code x,code y)
{
    return x.x < y.x || x.x == y.x && x.z > y.z;
}

il void build(int l, int r, int v)
{
    int mid = (l + r) >> 1;
    if (l == r)
    {
        f[v].sum = abs(l - maxn);
        return;
    }
    build(l, mid, v << 1);
    build(mid + 1, r, (v << 1) | 1);
} 
 
il void pushdown(int v)
{ 
    if (f[v].bz == 1) f[v << 1].bz = f[(v << 1) | 1].bz = 1;
    else if (f[v].bz == 2) f[v << 1].bz = f[(v << 1) | 1].bz = 2, f[v << 1].bz1 = f[(v << 1) | 1].bz1 = f[v].bz1;
    else if (f[v].bz == 3) f[v << 1].bz = f[(v << 1) | 1].bz = 3, f[v << 1].bz1 = f[(v << 1) | 1].bz1 = f[v].bz1;
} 
 
il void change(int l, int r, int v, int x, int y)
{ 
    int mid = (l + r) >> 1;
    if (x > y) return;
    if (f[v].bz)
    {
        if (l != r) pushdown(v);
        else if (f[v].bz == 1) f[v].sum = maxn * 1000;
        else if (f[v].bz == 2) f[v].sum = f[v].bz1 + l;
        else f[v].sum = f[v].bz1 - l;
        f[v].bz = 0;
    } 
    if (l >= x && r <= y)
    {
        f[v].bz = z;
        if (z != 1) f[v].bz1 = t;
        return; 
    } 
    if (l <= y && mid >= x) change(l, mid, v << 1, x, y);
    if (mid < y && r >= x) change(mid + 1, r, (v << 1) | 1, x, y);
}

il void find(int l, int r, int v, int x)
{
    int mid = (l + r) >> 1;
    if (f[v].bz)
    {
        if (l != r) pushdown(v);
        else if (f[v].bz == 1) f[v].sum = maxn * 1000;
        else if (f[v].bz == 2) f[v].sum = f[v].bz1 + l;
        else f[v].sum = f[v].bz1 - l;
        f[v].bz = 0;
    }
    if (l == r)
    {
        t = f[v].sum;
        return;
    }
    if (mid >= x) find(l, mid, v << 1, x);
    else find(mid + 1, r, (v << 1) | 1, x);
}

int main()
{
    scanf("%d%d%d", &sx, &sy, &n);
    sy += maxn;
    for (Int i = 1; i <= n; ++ i)
    {
        scanf("%d%d%d%d", &a[i].x, &a[i].y, &a[i + n].x, &a[i].yy), a[i].y += maxn, a[i].yy += maxn;
        if (a[i + n].x < a[i].x) a[i + n].z = 1;
        else a[i].z = 1;
        if (a[i].y > a[i].yy) swap(a[i].y, a[i].yy);
        a[i + n].y = a[i].y, a[i + n].yy = a[i].yy;
    }
    sort(a + 1, a + (n << 1) + 1, cmp);
    bz = 0;
    for (Int i = 1; i <= n << 1; ++ i)
    {
        if (a[i].x > sx) break;
        if (!bz) build(1, maxn << 1, 1);
        if (a[i].z) z = 1, change(1, maxn << 1, 1, a[i].y, a[i].yy);
        else
        {
            t = z = 0;
            find(1, maxn << 1, 1, a[i].y - 1);k = t;
            find(1, maxn << 1, 1, a[i].yy + 1);swap(t, k);
            x = (a[i].y + a[i].yy - t + k) >> 1;
            t -= a[i].y - 1;
            z = 2;
            change(1, maxn << 1, 1, a[i].y, min(a[i].yy, x));z = 3;t = k + a[i].yy + 1;
            change(1, maxn << 1, 1, max(a[i].y, x + 1), a[i].yy);
        }
        ++ bz;
    }
    t = 0;
    z = 1; 
    ans = 1e9;
    find(1, maxn << 1, 1, sy);
    t += sx;
    printf("%d\n", t);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值