1. 程式人生 > 實用技巧 >D:Returning Home-Codeforces Round #675 (Div. 2)

D:Returning Home-Codeforces Round #675 (Div. 2)

D:Returning Home-Codeforces Round #675 (Div. 2)

Problem:

Yura has been walking for some time already and is planning to return home. He needs to get home as fast as possible. To do this, Yura can use the instant-movement locations around the city.

Let's represent the city as an area of \(n×n\) square blocks. Yura needs to move from the block with coordinates \((sx,sy)\)

to the block with coordinates \((fx,fy)\). In one minute Yura can move to any neighboring by side block; in other words, he can move in four directions. Also, there are mm instant-movement locations in the city. Their coordinates are known to you and Yura. Yura can move to an instant-movement location in no time if he is located in a block with the same coordinate \(x\)
or with the same coordinate \(y\) as the location.

Help Yura to find the smallest time needed to get home.

Input:

The first line contains two integers nn and mm — the size of the city and the number of instant-movement locations (\(1≤n≤10^9, 0≤m≤10^5\)).

The next line contains four integers \(sx,sy,fx,fy\)

— the coordinates of Yura's initial position and the coordinates of his home (\(1≤sx,sy,fx,fy≤n\)).

Each of the next mm lines contains two integers \(xi,yi\) — coordinates of the \(i\)-th instant-movement location (\(1≤xi,yi≤n\)).

Output:

In the only line print the minimum time required to get home.

Examples:

input

5 3
1 1 5 5
1 2
4 1
3 3

output

5

input

84 5
67 59 41 2
39 56
7 2
15 3
74 18
22 7

output

42
Solution:

因為可以藉助location走捷徑,所以我們將所有location位置記錄後構造無向圖,因為任意兩個location都是可以互相到達的,所以這裡有\(m*(m-1)/2\)條邊,由於m最大為\(10^5\),顯然是無法存下這麼大的圖的,但是經過分析我們可以發現,假設存在兩個點\(l(x_1,y_1),r(x_2,y_2)\),兩點距離為\(min(abs(x_1-y_1),abs(x_2-y_2))\),如果存在第三個點\(k(x_3,y_3)\)且滿足\(x1 \leq x_3 \leq x_2\),則有\(dis[x_1,x_2] = dis[x_1,x_3] + dis[x_3, x_2]\),因此只需要建立\(edge[x_1,x_3] 和 edge[x_2,x_3]\),考慮\(x,y\)兩個方向,構造圖時只需要將所有點按照\(x\)\(y\)的座標排序之後建邊即可,構造圖之後,在構造圖上執行最短路演算法,對於起點計算\(sx,sy\)到每個點的距離,並進行最短路演算法,之後計算最短路徑加上該點到\(fx,fy\)的距離取其中的最小值即為答案。

Code:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

const int maxn = 811111;
const int inf = 0x3fffff;

typedef long long ll;

struct ad{
    int x, y, a;
    ad(int i, int j, int k) : x(i), y(j), a(k) {}
    ad() : x(0), y(0), a(0) {}
}loc[maxn];

bool cmp1(ad l, ad r) {
    if(l.x == r.x) return l.y < r.y;
    return l.x < r.x;
}

bool cmp2(ad l, ad r) {
    if(l.y == r.y) return l.x < r.x;
    return l.y < r.y;
}

ll first[maxn], nxt[maxn], cnt, v[maxn], w[maxn];
pair<int, int> poc[maxn];
ll dis[maxn];

void add(int x, int y, int d) {
    cnt++;
    v[cnt] = y; w[cnt] = d;
    nxt[cnt] = first[x]; first[x] = cnt;
    return;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int n, m, sx, sy, fx, fy;
    cin >> n >> m >> sx >> sy >> fx >> fy;
    for(int i = 1; i <= m; ++i) {
        int x, y;
        cin >> x >> y;
        poc[i] = make_pair(x, y);
        loc[i] = ad(x, y, i);
    }
    memset(first, -1, sizeof(first));
    memset(nxt, -1, sizeof(nxt));
    cnt = 0;
    sort(loc + 1, loc + 1 + m, cmp1);
    for(int i = 2; i <= m; ++i) {
        ad la = loc[i - 1];
        int ds = min(abs(loc[i].x - la.x), abs(loc[i].y - la.y));
        add(loc[i].a, la.a, ds);
        add(la.a, loc[i].a, ds);
    }
    sort(loc + 1, loc + 1 + m, cmp2);
    for(int i = 2; i <= m; ++i) {
        ad la = loc[i - 1];
        int ds = min(abs(loc[i].x - la.x), abs(loc[i].y - la.y));
        add(loc[i].a, la.a, ds);
        add(la.a, loc[i].a, ds);
    }
    priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>> box;
    for(int i = 1; i <= m; ++i) {
        dis[i] = min(abs(sx - poc[i].first), abs(sy - poc[i].second));
        box.push(make_pair(dis[i], i));
    }
    while(!box.empty()) {
        int wd, x;
        wd = box.top().first; x = box.top().second;
        box.pop();
        if(wd != dis[x]) continue;
        for(int i = first[x]; i != -1; i = nxt[i]) {
            int y = v[i];
            int c = w[i];
            if(dis[y] > wd + c) {
                dis[y] = wd + c;
                box.push(make_pair(dis[y], y));
            }
        }
    }
    ll ans = abs(sx - fx) + abs(sy - fy);
    for(int i = 1; i <= m; ++i) {
        ans = min(ans, dis[i] + abs(poc[i].first - fx) + abs(poc[i].second - fy));
    }
    cout << ans << endl;
    return 0;
}