Hướng dẫn giải của Bedao Mini Contest 21 - Qua đường


Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.

Tác giả: ntnguyen

Với mỗi truy vấn, ta nhận thấy đáp án sẽ tối ưu khi quay đầu một và chỉ một lần. Từ đó chia làm 3 case:

  • Rẽ tại ~pos_{min}~ mà ~pos >= x~. Nếu tồn tại ~pos~ thỏa mãn có thể quay đầu và ~pos - x <= k~, xét tiếp hai trường hợp con:

    • ~pos <= y~ : Đáp án là ~y - x~;

    • ~pos > y~ : Nếu ~(pos - x) + (pos - y) <= k~, đáp án là ~(pos - x) + (pos - y)~.

  • Rẽ tại ~pos_{min}~ mà ~y <= pos < x~ (Hiển nhiên case này chỉ xảy ra khi ~y < x~). Nếu tồn tại ~pos~ thỏa mãn có thể quay đầu và ~pos - y <= k~, đáp án là ~x - y~.

  • Rẽ tại ~pos_{max}~ mà ~pos < min(x, y)~. Nếu tồn tại ~pos~ thỏa mãn có thể quay đầu, đáp án là ~(x - pos) + (y - pos)~.

Lấy ~min~ của 3 case trên và ta có được đáp án của mỗi truy vấn.

Sử dụng cấu trúc dữ liệu set<pair <int, int> > để lưu trữ các đoạn được quay đầu.

Độ phức tạp tổng: ~O( (n+q) \cdot log2(n) )~.

Code mẫu

#include <bits/stdc++.h>
#define ll long long
#define N 200005
#define pii pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define getbit(x,y) (((x)>>(y))&1)
#define getoff(x,y) ((x)^(1<<(y)))

using namespace std;

int n, k, q;
pii a[N];
vector<int> vt;

void calc(int x, int y, int z, int &ans) {
    if (abs(z) == (int) 2e9) return;

    int res = abs(x - z) + abs(y - z); int bound = 0;
    if (x < z) bound += abs(x - z);
    if (y < z) bound += abs(y - z);

    if (bound <= k) ans = min(ans, res);
}

int main()
{
    //freopen(".inp", "r", stdin);
    //freopen(".out", "w", stdout);
    ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    cin >> n >> q;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i].first >> a[i].second;
        vt.push_back(a[i].first); vt.push_back(a[i].second);
    }

    sort(a + 1, a + n + 1);
    sort(vt.begin(), vt.end());

    while (q--) {
        int x, y; cin >> x >> y >> k;

        int lX = 1; int rX = n + 1;
        while (lX < rX) {
            int mid = (lX + rX) >> 1;
            if (a[mid].first > x) rX = mid;
            else lX = mid + 1;
        }

        --lX;
        if (lX == 0) lX = -2e9, rX = a[1].first;
        else if (a[lX].second >= x) lX = rX = x;
        else if (lX == n) rX = 2e9, lX = a[lX].second;
        else rX = a[lX + 1].first, lX = a[lX].second;

        int lY = 1; int rY = n + 1;
        while (lY < rY) {
            int mid = (lY + rY) >> 1;
            if (a[mid].first > y) rY = mid;
            else lY = mid + 1;
        }

        --lY;
        if (lY == 0) lY = -2e9, rY = a[1].first;
        else if (a[lY].second >= y) lY = rY = y;
        else if (lY == n) rY = 2e9, lY = a[lY].second;
        else rY = a[lY + 1].first, lY = a[lY].second;

        int res = (int) 2e9;
        calc(x, y, lX, res); calc(x, y, rX, res);
        calc(x, y, lY, res); calc(x, y, rY, res);

        if (res == (int) 2e9) res = -1;
        cout << res <<'\n';
    }

    return 0;
}

Bình luận

Hãy đọc nội quy trước khi bình luận.


Không có bình luận tại thời điểm này.