JZOJ5049 [GDOI2017模擬一試4.11] 腐女的生日

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章