Submission #1290572

#TimeUsernameProblemLanguageResultExecution timeMemory
1290572ProtonDecay314Nile (IOI24_nile)C++20
100 / 100
146 ms41144 KiB
#include "nile.h"
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<ll> vll;
typedef vector<int> vi;
typedef vector<vll> vvll;
typedef vector<vi> vvi;
typedef pair<int, int> pi;
typedef pair<ll, ll> pll;
typedef vector<pi> vpi;
typedef vector<pll> vpll;

#define pb push_back
#define INF(dt) numeric_limits<dt>::max()
#define NINF(dt) numeric_limits<dt>::min()

struct ParTree {
    ParTree* lt, *rt;
    ll l, r;
    pll v;

    ParTree(ll a_l, ll a_r): lt(nullptr), rt(nullptr), l(a_l), r(a_r), v({INF(ll), INF(ll)}) {}

    inline pll combine(pll lv, pll rv) {
        return {min(lv.first, rv.first), min(lv.second, rv.second)};
    }

    void build(const vll& a) {
        if(l == r) {
            if(l & 0b1ll) {
                // odd, put in second
                v.second = a[l];
            } else {
                v.first = a[l];
            }
            return;
        }

        ll m = (l + r) >> 1ll;

        lt = new ParTree(l, m);
        rt = new ParTree(m + 1ll, r);

        lt->build(a);
        rt->build(a);

        v = combine(lt->v, rt->v);
    }

    pll qry(ll ql, ll qr) {
        if(ql > r || qr < l) return {INF(ll), INF(ll)};

        if(ql == l && qr == r) return v;

        ll m = (l + r) >> 1ll;

        return combine(lt->qry(ql, min(qr, m)), rt->qry(max(ql, m + 1ll), qr));
    }
};

struct MinTree {
    MinTree *lt, *rt;
    ll l, r;
    ll v;

    MinTree(ll a_l, ll a_r): lt(nullptr), rt(nullptr), l(a_l), r(a_r), v(INF(ll)) {}

    inline ll combine(ll lv, ll rv) {
        return min(lv, rv);
    }

    void build(const vll& a) {
        if(l == r) {
            v = a[l];
            return;
        }

        ll m = (l + r) >> 1ll;

        lt = new MinTree(l, m);
        rt = new MinTree(m + 1ll, r);

        lt->build(a);
        rt->build(a);

        v = combine(lt->v, rt->v);
    }

    void upd(ll i, ll nv) {
        if(r < i || l > i) return;

        if(l == r) {
            v = nv;
            return;
        }

        ll m = (l + r) >> 1ll;

        if(i <= m) lt->upd(i, nv);
        else rt->upd(i, nv);

        v = combine(lt->v, rt->v);
    }

    ll qry(ll ql, ll qr) {
        if(ql > r || qr < l) return INF(ll);

        if(ql == l && qr == r) return v;
        ll m = (l + r) >> 1ll;

        return combine(lt->qry(ql, min(qr, m)), rt->qry(max(ql, m + 1ll), qr));
    }
};

struct DSU {
    /*
    DSU must include min and max index of the current component
    also, the updates for the values of each component must be separated
    into its own function

    so every time we update the value in the MinTree, we have to 
    call update on the corresponding value of the component in DSU
    */
    ll n;
    ll ncomps;
    vll par;
    vll csize;
    vll minc;
    vll cl; // left index of component
    vll cr; // right index of component
    ll curans;

    DSU(ll a_n, ll initans, const vll& a): n(a_n), ncomps(a_n), par(a_n, 0ll), csize(a_n, 1ll), minc(a_n, INF(ll)), cl(a_n, 0ll), cr(a_n, 0ll), curans(initans) {
        for(ll i = 0ll; i < n; i++) {
            cl[i] = cr[i] = par[i] = i;
            minc[i] = a[i];
        }
    }

    ll find(ll i) {
        return (i == par[i] ? i : par[i] = find(par[i]));
    }

    void unify(ll i, ll j, ParTree* ptr, MinTree* mtr, const vll& bpref) {
        ll pari = find(i);
        ll parj = find(j);

        if(pari == parj) return;

        ll prev_c = minc[pari] + minc[parj];

        ll npar;
        if(csize[pari] < csize[parj]) {
            // merge i into j
            npar = par[pari] = parj;
            csize[parj] += csize[pari];
        } else {
            // merge j into i
            npar = par[parj] = pari;
            csize[pari] += csize[parj];
        }
        cl[npar] = min(cl[pari], cl[parj]);
        cr[npar] = max(cr[pari], cr[parj]);

        minc[npar] = prev_c;

        upd(npar, ptr, mtr, bpref);
    }

    void upd(ll comp, ParTree* ptr, MinTree* mtr, const vll& bpref) {
        comp = find(comp);
        ll prval = minc[comp];

        // compute new cost
        // we must do casework on the size of the component
        ll cursz = csize[comp];

        if(cursz & 0b1ll) {
            // odd
            ll startpar = cl[comp] & 0b1ll;

            pll alt_min_pair = ptr->qry(cl[comp], cr[comp]);
            ll alt_min = (startpar ? alt_min_pair.second : alt_min_pair.first);

            minc[comp] = min(alt_min, mtr->qry(cl[comp], cr[comp])) + bpref[cr[comp] + 1ll] - bpref[cl[comp]];
        } else {
            // even
            minc[comp] = bpref[cr[comp] + 1ll] - bpref[cl[comp]];
            // cerr << "!! " << minc[comp] << endl;
        }
        
        // update total cost
        curans -= prval;
        curans += minc[comp];
    }
};

struct Query {
    ll qi, e;
};

typedef vector<Query> vq;
struct Artifact {
    ll w, a, b;
};

typedef vector<Artifact> va;

vll calculate_costs(vi w, vi a, vi b, vi e) {
    ll n = (ll)w.size();
    ll q = (ll)e.size();
    vll ans(q, 0);

    // Sorting queries into a vector for offline processing
    vq qs;
    
    for(ll i = 0ll; i < q; i++) {
        qs.pb({i, e[i]});
    }

    sort(qs.begin(), qs.end(), [](Query q1, Query q2) {return q1.e < q2.e;});

    // Storing artifacts in new format and sorting
    va arts;

    for(ll i = 0ll; i < n; i++) {
        arts.pb({w[i], a[i], b[i]});
    }

    sort(arts.begin(), arts.end(), [](Artifact v1, Artifact v2) {return v1.w < v2.w;});

    // Creating prefsum arrays for a and b

    vll prefa(n + 1ll, 0ll);

    for(ll i = 0ll; i < n; i++) {
        prefa[i + 1ll] = prefa[i] + arts[i].a;
    }

    vll prefb(n + 1ll, 0ll);

    for(ll i = 0ll; i < n; i++) {
        prefb[i + 1ll] = prefb[i] + arts[i].b;
    }

    // Creating vec of (diff, ind) pairs for updating MinTree
    vpll mintrupds;

    for(ll i = 1ll; i < n - 1ll; i++) {
        mintrupds.pb({arts[i + 1ll].w - arts[i - 1ll].w, i});
    }

    /// sort mintrupds by INCREASING order
    sort(mintrupds.begin(), mintrupds.end());

    // creating vec of (diff, ind) pairs for updating DSU
    vpll dsuupds;
    for(ll i = 0ll; i < n - 1ll; i++) {
        dsuupds.pb({arts[i + 1ll].w - arts[i].w, i});
    }

    sort(dsuupds.begin(), dsuupds.end());

    // Building Segtrees and DSU
    /// Building a[i] - b[i]
    vll amb(n, 0ll);
    for(ll i = 0ll; i < n; i++) amb[i] = arts[i].a - arts[i].b;

    /// building partree
    ParTree* ptr = new ParTree(0ll, n - 1ll);
    ptr->build(amb);

    /// mintree should store a[i] - b[i], initially INF
    MinTree* mtr = new MinTree(0ll, n - 1ll);
    vll mtrinit(n, INF(ll));
    mtrinit[0ll] = arts[0ll].a - arts[0ll].b;
    mtrinit[n - 1ll] = arts[n - 1ll].a - arts[n - 1ll].b;
    mtr->build(mtrinit);

    /// building DSU
    vll art_a_vals(n, 0ll);
    for(ll i = 0ll; i < n; i++) art_a_vals[i] = arts[i].a;
    DSU dsu(n, prefa[n], art_a_vals);

    // Answering queries offline
    ll qi = 0ll;
    ll mtrupdind = 0ll;
    ll dsuupdind = 0ll;

    while(qi < q) {
        ll curd = qs[qi].e;

        // update the DSU
        while(dsuupdind < n - 1ll && dsuupds[dsuupdind].first <= curd) {
            // cerr << "! " << dsuupds[dsuupdind].first << endl;
            ll updind = dsuupds[dsuupdind].second;
            dsu.unify(updind, updind + 1ll, ptr, mtr, prefb);
            dsuupdind++;
        }
        
        // update the MinTree
        while(mtrupdind < n - 2ll && mintrupds[mtrupdind].first <= curd) {
            ll updind = mintrupds[mtrupdind].second;
            mtr->upd(updind, arts[updind].a - arts[updind].b);
            
            dsu.upd(dsu.find(updind), ptr, mtr, prefb);
            mtrupdind++;
            
        }

        // answer
        ans[qs[qi].qi] = dsu.curans;
        
        qi++;
    }

    return ans;
}
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...