Submission #1294232

#TimeUsernameProblemLanguageResultExecution timeMemory
1294232nathako9nPalembang Bridges (APIO15_bridge)C++20
22 / 100
36 ms8664 KiB
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
typedef tree<pair<long long,long long>,null_type,less<pair<long long,long long>>,rb_tree_tag,tree_order_statistics_node_update> oset;
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
#define ll long long
#define all(x) (x).begin(), (x).end()
#define king ios::sync_with_stdio(false); cin.tie(nullptr);cout.tie(0)

int n, k, maxn;
oset st;
vector<ll> tr;      // sums
vector<int> trCnt;  // counts

// Fenwick for sums
ll queSum(int i){
    ll sm=0;
    for(; i>=1; i-=i&-i) sm += tr[i];
    return sm;
}
void upSum(int i,ll x){
    for(; i<=maxn; i+=i&-i) tr[i] += x;
}

// Fenwick for counts
int queCnt(int i){
    int sm=0;
    for(; i>=1; i-=i&-i) sm += trCnt[i];
    return sm;
}
void upCnt(int i,int x){
    for(; i<=maxn; i+=i&-i) trCnt[i] += x;
}

map<ll,int> pos;
ll totalSumAll = 0;

ll cal(bool useLeftMedian){
    if(st.size() == 0) return 0;
    // choose median index (order in st)
    size_t sz = st.size();
    size_t posIndex;
    if(useLeftMedian){
        // left median for even size
        posIndex = sz/2 - 1;
    } else {
        // right median for even size
        posIndex = sz/2;
    }
    // get iterator to that ordered element
    auto it = st.find_by_order(posIndex);
    ll x = it->first;
    // compressed position of value x
    int p = pos[x];

    // counts and sums strictly less than value x
    int countLess = queCnt(p-1);
    ll sumLess = queSum(p-1);

    // total count left of chosen pair in st (including equal-values that are before this pair)
    int countLeft = (int)posIndex;
    // number of equal-value elements that are before the chosen pair
    int equalBefore = countLeft - countLess;
    // low should include sumLess plus equalBefore * x
    ll low = sumLess + (ll)equalBefore * x;

    // counts and sums strictly greater than value x
    int countGreater = queCnt(maxn) - queCnt(p);
    ll sumGreater = queSum(maxn) - queSum(p);
    // number of elements strictly after chosen pair in st
    int countRight = (int)sz - (int)posIndex - 1;
    // sum of elements after chosen pair equals sumGreater (elements equal to x after the chosen pair contribute 0 to distance)
    ll hi = sumGreater;

    ll leftCost = x * (ll)countLeft - low;
    ll rightCost = hi - x * (ll)countRight;
    return leftCost + rightCost;
}

vector<tuple<ll,ll,ll>> vec;
vector<ll> pf, suf;

int main(){
    king;
    cin >> k >> n;
    maxn = 2 * n + 5;
    tr.assign(maxn + 5, 0);
    trCnt.assign(maxn + 5, 0);

    vector<ll> com;
    vector<ll> k1;
    ll ans = 0;

    for(int i = 1; i <= n; ++i){
        char q,w;
        int x,y;
        cin >> q >> x >> w >> y;
        if(q == w){
            ans += llabs((ll)x - (ll)y);
        } else {
            ans++;
            vec.push_back({(x + y) / 2, x, y});
            if(k == 1){
                k1.push_back(x);
                k1.push_back(y);
            }
        }
        com.push_back(x);
        com.push_back(y);
    }

    if(k == 1){
        if(k1.empty()){
            cout << ans << '\n';
            return 0;
        }
        sort(all(k1));
        size_t m = k1.size();
        size_t mid = m/2;
        // choose left median (either left or right median gives same minimal sum for even count)
        if(mid == 0){
            cout << ans << '\n';
            return 0;
        }
        mid = mid - 1;
        ll x = k1[mid];
        ll low = 0, hi = 0;
        for(size_t i = 0; i < mid; ++i) low += k1[i];
        for(size_t i = mid+1; i < m; ++i) hi += k1[i];
        cout << ans + (x * (ll)mid - low) + (hi - x * (ll)(mid + 1)) << '\n';
        return 0;
    }

    sort(all(com));
    com.erase(unique(all(com)), com.end());
    for(size_t i = 0; i < com.size(); ++i) pos[com[i]] = (int)(i + 1);

    if(vec.empty()){
        cout << ans << '\n';
        return 0;
    }

    pf.assign(vec.size(), 0);
    suf.assign(vec.size(), 0);

    // prefix pass (use left median)
    size_t cnt = 0;
    for(size_t i = 0; i < vec.size(); ++i){
        auto [s,x,y] = vec[i];
        st.insert({x, cnt++});
        st.insert({y, cnt++});
        upSum(pos[x], x);
        upSum(pos[y], y);
        upCnt(pos[x], 1);
        upCnt(pos[y], 1);
        pf[i] = cal(true); // left median
    }

    // suffix pass: clear and rebuild from reversed vec (use right median)
    st.clear();
    fill(tr.begin(), tr.end(), 0);
    fill(trCnt.begin(), trCnt.end(), 0);
    cnt = 0;
    reverse(all(vec));
    for(size_t i = 0; i < vec.size(); ++i){
        auto [s,x,y] = vec[i];
        st.insert({x, cnt++});
        st.insert({y, cnt++});
        upSum(pos[x], x);
        upSum(pos[y], y);
        upCnt(pos[x], 1);
        upCnt(pos[y], 1);
        suf[(vec.size()-1) - i] = cal(false); // right median
    }

    ll mn = (ll)4e18;
    if(vec.size() == 1){
        mn = min(pf[0], suf[0]);
    } else {
        for(size_t i = 0; i + 1 < vec.size(); ++i){
            mn = min(mn, pf[i] + suf[i+1]);
        }
    }

    cout << mn + ans << '\n';
    return 0;
}
#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...