Submission #1317381

#TimeUsernameProblemLanguageResultExecution timeMemory
1317381spetrNile (IOI24_nile)C++20
100 / 100
69 ms13588 KiB
#include <vector>
#include <algorithm>
#include <numeric>

using namespace std;

typedef long long ll;

const ll INF = 1e18; // Dostatečně velké nekonečno

struct Artifact {
    int id;
    int w;
    ll diff; // Penalizace (A - B)
};

struct Event {
    int w;     // Váha (threshold)
    int type;  // 1: Sousedé (i, i+1), 2: Skok (i, i+2), 3: Dotaz
    int idx;   // Index
    
    // Řazení: primárně podle váhy, sekundárně typ (hrany dříve než dotazy)
    bool operator<(const Event& other) const {
        if (w != other.w) return w < other.w;
        return type < other.type;
    }
};

struct DSU {
    vector<int> parent;
    vector<int> sz;           // Velikost komponenty
    vector<int> min_idx;      // Nejnižší globální index v komponentě (určuje paritu majority)
    
    // min_diff[0]: Nejmenší penalizace (A-B) pro globálně SUDÝ prvek v této komponentě
    // min_diff[1]: Nejmenší penalizace (A-B) pro globálně LICHÝ prvek v této komponentě
    vector<ll> min_diff[2];   

    // min_jump_diff[0]: Nejmenší penalizace SUDÉHO prvku, který je "přeskočen" aktivním skokem
    // min_jump_diff[1]: Nejmenší penalizace LICHÉHO prvku, který je "přeskočen" aktivním skokem
    vector<ll> min_jump_diff[2];

    ll current_total_penalty = 0;

    DSU(int n, const vector<Artifact>& arts) {
        parent.resize(n);
        iota(parent.begin(), parent.end(), 0);
        sz.assign(n, 1);
        min_idx.resize(n);
        
        min_diff[0].assign(n, INF);
        min_diff[1].assign(n, INF);
        min_jump_diff[0].assign(n, INF);
        min_jump_diff[1].assign(n, INF);

        for(int i=0; i<n; ++i) {
            min_idx[i] = i;
            min_diff[i%2][i] = arts[i].diff;
            // Na začátku je každý sám -> lichá komponenta -> platí penalizaci
            current_total_penalty += arts[i].diff;
        }
    }

    // Find s kompresí cesty
    int find(int i) {
        if (parent[i] == i) return i;
        return parent[i] = find(parent[i]);
    }

    // Výpočet penalizace pro jednu komponentu
    ll get_penalty(int root) {
        // Pokud je komponenta sudá, všichni se spárují -> penále 0
        if (sz[root] % 2 == 0) return 0; 

        // Komponenta je lichá -> jeden musí zůstat sám (zaplatí A-B)
        // Která parita je "většinová"? Ta, kterou má začátek komponenty (min_idx).
        int major_parity = min_idx[root] % 2;
        int minor_parity = 1 - major_parity;

        // Základní možnost: Obětujeme nejlevnějšího z majority
        ll cost = min_diff[major_parity][root];

        // Možnost skoku: Obětujeme někoho z minority, ALE jen pokud byl "přeskočen"
        // (Tj. existuje aktivní skok přes něj)
        cost = min(cost, min_jump_diff[minor_parity][root]);
        
        return cost;
    }

    void unite(int i, int j) {
        int root_i = find(i);
        int root_j = find(j);

        if (root_i != root_j) {
            // OPTIMALIZACE: Union by Size (připojujeme menší k většímu)
            // Toto je kritické proti TLE
            if (sz[root_i] < sz[root_j]) swap(root_i, root_j);

            // 1. Odečteme staré penalizace
            current_total_penalty -= get_penalty(root_i);
            current_total_penalty -= get_penalty(root_j);

            // 2. Sloučení dat do root_i
            parent[root_j] = root_i;
            sz[root_i] += sz[root_j];
            
            min_idx[root_i] = min(min_idx[root_i], min_idx[root_j]);
            
            min_diff[0][root_i] = min(min_diff[0][root_i], min_diff[0][root_j]);
            min_diff[1][root_i] = min(min_diff[1][root_i], min_diff[1][root_j]);
            
            min_jump_diff[0][root_i] = min(min_jump_diff[0][root_i], min_jump_diff[0][root_j]);
            min_jump_diff[1][root_i] = min(min_jump_diff[1][root_i], min_jump_diff[1][root_j]);

            // 3. Přičteme novou penalizaci
            current_total_penalty += get_penalty(root_i);
        }
    }

    // Aktivace skoku (typ 2)
    // Hrana (i, i+2) přeskakuje prvek m = i+1.
    void activate_jump(int i, const vector<Artifact>& arts) {
        int skipped_idx = i + 1;
        int p = skipped_idx % 2; // Parita přeskočeného prvku
        
        int root = find(i); // Hledáme kořen komponenty, kde skok je
        
        // Zkontrolujeme, jestli se tímto skokem nezlepší "min_jump_diff" pro danou paritu
        if (arts[skipped_idx].diff < min_jump_diff[p][root]) {
            current_total_penalty -= get_penalty(root);
            min_jump_diff[p][root] = arts[skipped_idx].diff;
            current_total_penalty += get_penalty(root);
        }
    }
};

std::vector<long long> calculate_costs(
    std::vector<int> W, std::vector<int> A, 
    std::vector<int> B, std::vector<int> E) {

    int n = W.size();
    vector<Artifact> arts(n);
    ll base_cost = 0; 

    for(int i=0; i<n; ++i) {
        arts[i] = {i, W[i], (ll)A[i] - B[i]};
        base_cost += B[i];
    }

    // Seřadíme podle váhy W
    sort(arts.begin(), arts.end(), [](const Artifact& a, const Artifact& b){
        return a.w < b.w;
    });

    // Vytvoříme události
    vector<Event> events;
    events.reserve(2 * n + E.size()); 

    // Hrany Type 1: (i, i+1)
    for(int i=0; i < n-1; ++i) {
        events.push_back({arts[i+1].w - arts[i].w, 1, i});
    }
    // Hrany Type 2: (i, i+2) - Skoky
    for(int i=0; i < n-2; ++i) {
        events.push_back({arts[i+2].w - arts[i].w, 2, i});
    }
    // Dotazy
    for(int i=0; i < E.size(); ++i) {
        events.push_back({E[i], 3, i});
    }

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

    // Inicializace DSU (musí pracovat s indexy po seřazení 0..N-1)
    DSU dsu(n, arts);
    vector<ll> results(E.size());

    for(const auto& ev : events) {
        if (ev.type == 1) {
            dsu.unite(ev.idx, ev.idx+1);
        } else if (ev.type == 2) {
            // Index v eventu je 'i', skok je přes 'i+1' (v seřazeném poli)
            dsu.activate_jump(ev.idx, arts);
        } else {
            // Query
            results[ev.idx] = base_cost + dsu.current_total_penalty;
        }
    }

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