Submission #1124193

#TimeUsernameProblemLanguageResultExecution timeMemory
1124193macneilPassport (JOI23_passport)C++20
100 / 100
821 ms172860 KiB
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define int long long
#define pb push_back
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
#define f(a) for(int i = 0; i<a; ++i)
#define deb(a) cerr<<a<<endl;
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef string str;
typedef vector<str> vestr;
typedef vector<int> vei;
typedef vector<vector<int>> veve;

struct SparseTable {
    vector<pair<int, int>> a;
    vector<vector<int>> spmin, spmax;

    SparseTable() {}
    
    void build(vector<pair<int, int>> c) {
        a = c;
        int n = a.size();
        int log2n = log2(n) + 1;
        spmin.resize(log2n, vector<int>(n));
        for (int i = 0; i < n; ++i) spmin[0][i] = i;
        for (int i = 1; i < log2n; ++i) {
            for (int j = 0; j < n; ++j) {
                int t = min(j + (1<<(i-1)), n - 1);
                if (a[spmin[i - 1][j]] < a[spmin[i - 1][t]]) spmin[i][j] = spmin[i - 1][j];
                else spmin[i][j] = spmin[i - 1][t];
            }
        }
        spmax.resize(log2n, vector<int>(n));
        for (int i = 0; i < n; ++i) spmax[0][i] = i;
        for (int i = 1; i < log2n; ++i) {
            for (int j = 0; j < n; ++j) {
                int t = min(j + (1<<(i-1)), n - 1);
                if (a[spmax[i - 1][j]] > a[spmax[i - 1][t]]) spmax[i][j] = spmax[i - 1][j];
                else spmax[i][j] = spmax[i - 1][t];
            }
        }
    }

    int min_ind(int l, int r) {
        int lg2 = log2(r - l + 1);
        r++;
        if (a[spmin[lg2][l]] < a[spmin[lg2][r - (1<<lg2)]]) return spmin[lg2][l];
        return spmin[lg2][r - (1<<lg2)];
    }

    pair<int, int> get_min(int l, int r) {
        int lg2 = log2(r - l + 1);
        r++;
        if (a[spmin[lg2][l]] < a[spmin[lg2][r - (1<<lg2)]]) return a[spmin[lg2][l]];
        return a[spmin[lg2][r - (1<<lg2)]];
    }

    int max_ind(int l, int r) {
        int lg2 = log2(r - l + 1);
        r++;
        if (a[spmax[lg2][l]] > a[spmax[lg2][r - (1<<lg2)]]) return spmax[lg2][l];
        return spmax[lg2][r - (1<<lg2)];
    }

    pair<int, int> get_max(int l, int r) {
        int lg2 = log2(r - l + 1);
        r++;
        if (a[spmax[lg2][l]] > a[spmax[lg2][r - (1<<lg2)]]) return a[spmax[lg2][l]];
        return a[spmax[lg2][r - (1<<lg2)]];
    }
};


const int INF = 1e8;

struct Node {
    pair<int, int> mx;
};

 
struct SegmentTree {
    vector<Node> tr;
    int sz;
 
    SegmentTree(vector<int> a) {
        int n = a.size();
        sz = (1ll<<(int)(log2(n)))*2;
        tr.resize(2*sz);
        for (int i = 0; i < 2 * sz; ++i) tr[i] = {{-INF, -INF}};
        for (int i = 0; i < n; ++i) {
            tr[i + sz - 1] = {{a[i], i}};
        }
        for (int i = sz - 2; i >= 0; --i) tr[i] = merge(tr[2 * i + 1], tr[2 * i + 2]);
    }

    Node merge(Node a, Node b) {
        return {max(a.mx, b.mx)};
    }
 
    Node get(int v, int l, int r, int ql, int qr) {
        if(ql <= l && qr >= r) {
            return tr[v];
        }
        if(l >= qr || r <= ql) return {{-INF, -INF}};
        int m = (l + r) / 2;
        return merge(get(2 * v + 1, l, m, ql, qr), get(2 * v + 2, m, r, ql, qr));
    };
 
    Node get(int ql, int qr) {
        return get(0, 0, sz, ql, qr);
    } 
 
    void update(int v, int l, int r, int ind, pair<int, int> x) {
        if(l > ind || r <= ind) return;
        if(r == l + 1) {
            tr[v].mx = x;
            return;
        }
        int m = (l + r) / 2;
        update(2*v+1, l, m, ind, x);
        update(2*v+2, m, r, ind, x);
        tr[v].mx = max(tr[2*v+1].mx, tr[2*v+2].mx);
    }
 
    void update(int ind) {
        pair<int, int> x = {-INF, -INF};
        update(0, 0, sz, ind, x);
    }
};
 
struct SegmentTree2 {
    vector<Node> tr;
    int sz;
 
    SegmentTree2(vector<int> a) {
        int n = a.size();
        sz = (1ll<<(int)(log2(n)))*2;
        tr.resize(2*sz);
        for (int i = 0; i < 2 * sz; ++i) tr[i] = {{INF, INF}};
        for (int i = 0; i < n; ++i) {
            tr[i + sz - 1] = {{a[i], i}};
        }
        for (int i = sz - 2; i >= 0; --i) tr[i] = merge(tr[2 * i + 1], tr[2 * i + 2]);
    }

    Node merge(Node a, Node b) {
        return {min(a.mx, b.mx)};
    }
 
    Node get(int v, int l, int r, int ql, int qr) {
        if(ql <= l && qr >= r) {
            return tr[v];
        }
        if(l >= qr || r <= ql) return {{INF, INF}};
        int m = (l + r) / 2;
        return merge(get(2 * v + 1, l, m, ql, qr), get(2 * v + 2, m, r, ql, qr));
    };
 
    Node get(int ql, int qr) {
        return get(0, 0, sz, ql, qr);
    } 
 
    void update(int v, int l, int r, int ind, pair<int, int> x) {
        if(l > ind || r <= ind) return;
        if(r == l + 1) {
            tr[v].mx = x;
            return;
        }
        int m = (l + r) / 2;
        update(2*v+1, l, m, ind, x);
        update(2*v+2, m, r, ind, x);
        tr[v].mx = min(tr[2*v+1].mx, tr[2*v+2].mx);
    }
 
    void update(int ind) {
        pair<int, int> x = {INF, INF};
        update(0, 0, sz, ind, x);
    }
};


void solve() {
    int n;
    cin >> n;
    vector<int> l(n), r(n);
    f(n) {
        cin >> l[i] >> r[i];
        l[i]--;
        r[i]--;
    }
    // if (n > 2500) {
    //     int q, k;
    //     cin >> q >> k;
    //     int ans = 1, R = r[0], R2 = 0;
    //     while (R != n - 1) {
    //         int tt = 0;
    //         for (int i = R2 + 1; i <= R; ++i) {
    //             tt = max(tt, r[i]);
    //         }
    //         if (tt <= R) {
    //             ans = -1;
    //             break;
    //         }
    //         ans++;
    //         R2 = R;
    //         R = tt;
    //     }
    //     cout << ans << '\n';
    //     return;
    // }
    set<pair<pair<int, int>, int>> ord;  // {{dp[i], r[i]}, i}
    // for (auto e : ord) cout << e << ' '; cout << '\n';
    vector<bool> used(n);
    vector<pair<int, int>> dp1(n, {1e8, 1e8});
    SegmentTree cur(r);
    SegmentTree2 cur2(l);
    f(n) if (l[i] == 0) ord.insert({{1, -r[i]}, i});
    f(n) if (l[i] == 0) used[i] = 1;
    f(n) if (l[i] == 0) dp1[i].first = 1;
    f(n) if (l[i] == 0) dp1[i].second = -r[i];
    f(n) if (l[i] == 0) cur.update(i);
    f(n) if (l[i] == 0) cur2.update(i);
    while(ord.size()) {
        int i = (*ord.begin()).second;
        // cout << i << ' ';
        dp1[i].second = min(dp1[i].second, -r[i]);
        while(1) {
            pair<int, int> au = cur.get(0, i).mx;
            // cout << au.second << endl;
            if (au.first < i) break;
            swap(au.first, au.second);
            dp1[au.first] = {dp1[i].first + 1, dp1[i].second};
            dp1[au.first].second = min(dp1[au.first].second, -r[au.first]);
            ord.insert({dp1[au.first], au.first});
            cur.update(au.first);
            cur2.update(au.first);
        }
        while(1) {
            pair<int, int> au = cur2.get(i, n).mx;
            if (au.first > i) break;
            swap(au.first, au.second);
            dp1[au.first] = {dp1[i].first + 1, dp1[i].second};
            dp1[au.first].second = min(dp1[au.first].second, -r[au.first]);
            ord.insert({dp1[au.first], au.first});
            cur.update(au.first);
            cur2.update(au.first);
        }
        // cout << endl;
        ord.erase(ord.begin());
    }
    // for (auto e : dp1) cout << e.first << ' '; cout << '\n';
    // for (auto e : ord) cout << e << ' '; cout << '\n';
    vector<pair<int, int>> dp2(n, {1e8, 1e8});
    SegmentTree cur3(r);
    SegmentTree2 cur4(l);
    used.clear();
    used.resize(n);
    f(n) if (r[i] == n - 1) ord.insert({{1, l[i]}, i});
    f(n) if (r[i] == n - 1) used[i] = 1;
    f(n) if (r[i] == n - 1) dp2[i].first = 1;
    f(n) if (r[i] == n - 1) dp2[i].second = l[i];
    f(n) if (r[i] == n - 1) cur3.update(i);
    f(n) if (r[i] == n - 1) cur4.update(i);
    while(ord.size()) {
        int i = (*ord.begin()).second;
        dp2[i].second = min(dp2[i].second, l[i]);
        while(1) {
            pair<int, int> au = cur3.get(0, i).mx;
            if (au.first < i) break;
            swap(au.first, au.second);
            dp2[au.first] = {dp2[i].first + 1, dp2[i].second};
            dp2[au.first].second = min(dp2[au.first].second, l[au.first]);
            ord.insert({dp2[au.first], au.first});
            cur3.update(au.first);
            cur4.update(au.first);
        }
        while(1) {
            pair<int, int> au = cur4.get(i, n).mx;
    // cout << "WOW" << au.first << endl;
            if (au.first > i) break;
            swap(au.first, au.second);
            dp2[au.first] = {dp2[i].first + 1, dp2[i].second};
            dp2[au.first].second = min(dp2[au.first].second, l[au.first]);
            ord.insert({dp2[au.first], au.first});
            cur3.update(au.first);
            cur4.update(au.first);
        }
        ord.erase(ord.begin());
    }
    // for (auto e : dp1) cout << e.first << ' '; cout << '\n';
    int q;
    cin >> q;
    SparseTable fdp1, fdp2;
    fdp1.build(dp1);
    fdp2.build(dp2);
    for (int i = 0; i < q; ++i) {
        int x;
        cin >> x;
        --x;
        if (dp1[x].first > 2 * n || dp2[x].first > 2 * n) {
            cout << "-1\n";
            continue;
        }
        int ans = dp1[x].first;
        if (dp1[x].second != -(n - 1)) ans += fdp2.get_min(0, -dp1[x].second).first;
        int ans2 = dp2[x].first;
        if (dp2[x].second != 0) ans2 += fdp1.get_min(dp2[x].second, n - 1).first;
        cout << min(ans, ans2) << '\n';
    }
}

signed main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    // freopen("a.in", "r", stdin);
    // freopen("a.out", "w", stdout);
    int tc = 1;
    // cin >> tc;
    for (int t = 1; t <= tc; t++) {
        // cout << "Case #" << t  << ": ";
        solve();
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...