H. Take the Elevator

Solution

上行下行两个方向显然分开考虑,一次上下取两者需要移动距离的较大值。
考虑上行时,上升高度取决于最大的bib_i,因此考虑将bib_i大的先满足,在取满mmbib_i最大的之后,考虑用大根堆维护已选乘客的aia_i最大值,接下来可以将bjmax{ai}b_j\le \max\{a_i\}的乘客加入(相当于有人在ii上电梯前下电梯),持续维护直到无法找到jj
考虑下行时,上升高度取决于最大的aia_i,因此考虑将aia_i大的先满足,在取满mmaia_i最大的之后,考虑用大根堆维护已选乘客的bib_i最大值,接下来可以将ajmax{bi}a_j\le \max\{b_i\}的乘客加入(相当于有人在ii下电梯后上电梯),持续维护直到无法找到jj
对比两个方向,可以发现操作完全一致。
时间复杂度O(nlogn)O(n\log n)

void solve(multiset<pair<int, int> > &st, int m) {
    priority_queue<int>pq;
    for (int i = 0; i < m && !st.empty(); ++i) {
        pq.push((*st.rbegin()).second);
        st.erase(st.lower_bound(*st.rbegin()));
    }
    while (!st.empty()) {
        auto it = st.lower_bound(make_pair(pq.top() + 1, 0));
        if (it == st.begin())break;
        if (it == st.end())it = st.lower_bound(*st.rbegin());
        else it = prev(it);
        pq.pop();
        pq.push(it -> second);
        st.erase(it);
    }
}

int main() {
    int n = fast_IO::read(), m = fast_IO::read(), k = fast_IO::read();
    multiset<pair<int, int> >up, down;
    for (int i = 1; i <= n; ++i) {
        int l = fast_IO::read(), r = fast_IO::read();
        if (l < r) {
            up.insert(make_pair(r, l));
        }
        else {
            down.insert(make_pair(l, r));
        }
    }
    ll ans = 0;
    while (!up.empty() || !down.empty()) {
        int ansup = 0, ansdown = 0;
        if (!up.empty()) {
            ansup = (*up.rbegin()).first - 1;
            solve(up, m);
        }
        if (!down.empty()) {
            ansdown = (*down.rbegin()).first - 1;
            solve(down, m);
        }
        ans += max(ansup, ansdown) * 2;
    }
    printf("%lld", ans);
    return 0;
}