제출 #1365392

#제출 시각아이디문제언어결과실행 시간메모리
1365392leolin0214은하철도 (APIO24_train)C++20
100 / 100
354 ms136644 KiB
#include "train.h"

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <queue>
#include <string.h>

#define ff first
#define ss second

using namespace std;

constexpr int capacity = 5e6;
int ptr = 0;
struct Node {int val, lc, rc;};
Node st[capacity];

struct PersistentSegmentTree {
    int n;
    
    int root = 0;
    PersistentSegmentTree() {}
    PersistentSegmentTree(int _n) : n(_n), root(0) {}
    void reset() {memset(st, 0, sizeof(st)); ptr = 1; root = 0;}
    int copy_node(int rt) {st[ptr] = st[rt]; return ptr++;}
    int modify(int qi, int qx) {return root = modify(qi, qx, 0, n-1, root);}
    int modify(int qi, int qx, int l, int r, int rt) {
        rt = copy_node(rt);
        if (l == r) {
            st[rt].val += qx;
            return rt;
        }
        int m = l + r >> 1;
        auto &[val, lc, rc] = st[rt];
        if (qi <= m) {
            lc = modify(qi, qx, l, m, lc);
        }else{
            rc = modify(qi, qx, m+1, r, rc);
        }
        val = st[lc].val + st[rc].val;
        return rt;
    }
    int query(int ql, int qr, int root) {return query(ql, qr, 0, n-1, root);}
    int query(int ql, int qr, int l, int r, int rt) {
        if (rt == 0) return 0;
        if (qr < l || r < ql) return 0;
        if (ql <= l && r <= qr) return st[rt].val;
        int m = l + r >> 1;
        auto &[val, lc, rc] = st[rt];
        return (
            query(ql, qr, l, m, lc) +
            query(ql, qr, m+1, r, rc) 
        );
    }
};

struct DataStructure {
    int n;
    PersistentSegmentTree st;
    vector<int> root;
    DataStructure(int _n, vector<pair<int, int>> seg) : n(_n), st(_n) {
        st.reset();
        vector<vector<int>> table(n);
        for (auto [l, r]: seg) table[r].push_back(l);
        int rt = 0;
        for (int r=0; r<n; r++) {
            for (int l: table[r]) rt = st.modify(l, +1);
            root.push_back(rt);
        }
    }
    int query(int ql, int qr) {
        if (ql > qr) return 0;
        return st.query(ql, n-1, root[qr]);
    }
};

long long solve(int n, int m, int w, std::vector<int> t, std::vector<int> x, std::vector<int> y,
                std::vector<int> a, std::vector<int> b, std::vector<int> c, std::vector<int> l,
                std::vector<int> r) 
{

    // relabeling timeline
    int z = 0;
    {
        vector<int> tb;
        tb.reserve(m*2 + w*2 + 10);
        for (int &i: a) tb.push_back(i);
        for (int &i: b) tb.push_back(i);
        for (int &i: l) tb.push_back(i);
        for (int &i: r) tb.push_back(i);
        tb.push_back(-1);
        tb.push_back(1e9+1);
        sort(tb.begin(), tb.end());
        tb.erase(unique(tb.begin(), tb.end()), tb.end());
        auto get_id = [&] (int i) -> int {return lower_bound(tb.begin(), tb.end(), i) - tb.begin();};
        for (int &i: a) i = get_id(i);
        for (int &i: b) i = get_id(i);
        for (int &i: l) i = get_id(i);
        for (int &i: r) i = get_id(i);
        z = tb.size();
    }

    vector<pair<int, int>> lr(w);
    for (int i=0; i<w; i++) lr[i] = {l[i], r[i]};

    DataStructure ds(z, lr);

    // debug
    // {
    //     cout << "cost:\t"; for (int i: t) cout << i << " "; cout << "\n";
    //     cout << "edge:\n";
    //     for (int i=0; i<m; i++) cout << x[i] << " -> " << y[i] << ": " << c[i] << " -- [" << a[i] << " ~ " << b[i] << "]\n";
    //     cout << "meal:\n";
    //     for (int i=0; i<w; i++) cout << "[" << l[i] << " ~ " << r[i] << "]\n";

    //     cout << "\n\ncount: \n";
    //     for (int i=0; i<z; i++) {
    //         for (int j=0; j<z; j++) {
    //             cout << (j < i ? 0 : ds.query(i, j)) << " ";
    //         }
    //         cout << "\n";
    //     }
    //     cout << "\n\n";
    // }

    vector<pair<int, int>> ev;
    ev.reserve(m*2 + 10);
    for (int i=0; i<m; i++) {
        ev.push_back({i, +1});
        ev.push_back({i, -1});
    }

    sort(ev.begin(), ev.end(), [&] (pair<int, int> x, pair<int, int> y) -> bool {
        int tx = x.ss == 1 ? b[x.ff] : a[x.ff];
        int ty = y.ss == 1 ? b[y.ff] : a[y.ff];
        if (tx == ty) return x.ss > y.ss;
        return tx < ty;
    });

    // Object: {cost, arrival_time, opt_left, opt_right}

    struct DequeObject {int id, l, r;};

    vector<long long> dp(m);
    vector<deque<DequeObject>> dq(n);

    // first
    {a.push_back(0);
    b.push_back(0);
    c.push_back(0);
    x.push_back(0);
    y.push_back(0);
    dp.push_back(0);}

    // last
    {a.push_back(z-1);
    b.push_back(z-1);
    c.push_back(0);
    x.push_back(n-1);
    y.push_back(n-1);
    dp.push_back(0);}

    auto calc_cost = [&] (int frm, int departure) -> long long {
        int v = y[frm];
        int arrival = b[frm];
        long long meal = t[v];
        if (arrival > departure) return 1e18;
        long long cnt = ds.query(arrival + 1, departure - 1);
        return dp[frm] + cnt * meal;
    };

    auto compare_moment = [&] (int frm1, int frm2, int departure) -> bool {
        return calc_cost(frm1, departure) < calc_cost(frm2, departure);
        // long long c1 = calc_cost(frm1, departure);
        // long long c2 = calc_cost(frm2, departure);
        // if (frm1 == 4 && frm2 == 0) {
        //     cout << "at " << departure << ": " << c1 << " v.s. " << c2 << "\n";
        // }
        // return c1 < c2; 
    };

    auto insert_object = [&] (deque<DequeObject> &dq, int id) -> void {
        while (dq.size() && compare_moment(id, dq.back().id, dq.back().l)) {
            dq.pop_back();
        }
        int arrival = b[id];
        if (dq.size()) {
            int l = max(arrival - 1, dq.back().l);
            int r = dq.back().r + 1;
            // if (id == 4) cout << dq.back().id << ": " << l << " ~ " << r << " rival\n";
            while (l+1 < r) {
                int m = l + r >> 1;
                if (compare_moment(id, dq.back().id, m)) {
                    r = m;
                }else{
                    l = m;
                }
            }
            dq.back().r = l;
            if (l+1 <= z-1) {
                dq.push_back({id, l+1, z-1});
            }
        }else{
            if (arrival <= z-1) {
                dq.push_back({id, arrival, z-1});
            }
        }
    };

    auto find_best = [&] (deque<DequeObject> &dq, int go) -> long long {
        int u = x[go];
        int departure = a[go];
        while (dq.size() && dq.front().r < departure) dq.pop_front();
        if (!dq.size()) return 1e18;
        return calc_cost(dq.front().id, departure);
    };

    insert_object(dq[0], m);

    for (auto [id, ty]: ev) {
        if (ty == +1) {
            int v = y[id];
            insert_object(dq[v], id);
        }else{
            int u = x[id];
            dp[id] = find_best(dq[u], id) + c[id];
        }
    }

    long long ans = find_best(dq[n-1], m+1);
    if (ans >= 1e18) ans = -1;
	return ans;
}
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…