Submission #991228

#TimeUsernameProblemLanguageResultExecution timeMemory
991228model_codeJobs (BOI24_jobs)C++17
100 / 100
331 ms54856 KiB
#include <iostream>
#include <vector>
#include <queue>

using namespace std;

const int N_MAX = 300000;

struct block {
    // Minimum prefix sum of the block -> we need at least "requirement" money to take all of block's elements
    long long requirement;
    // Sum of all elements of the block
    long long sum;

    // Allows sorting blocks in non-decreasing order by "requirement"
    bool operator>(const block& other) const {
        return requirement > other.requirement || (requirement == other.requirement && sum > other.sum);
    }
};

int x[N_MAX + 1];
vector <int> children[N_MAX + 1];

// Index of the 'leader' vertex of a priority queue containing vertex i
int p_queue_index[N_MAX + 1];
// Structure allowing to extract block with the smallest "requirement" value
priority_queue <block, vector<block>, greater<block>> blocks[N_MAX + 1];


int merge_priority_queues(int id_a, int id_b) {
    if (blocks[id_b].size() > blocks[id_a].size()) {
        // Trick: merge smaller queue to a larger one
        swap(id_a, id_b);
    }
    while (blocks[id_b].size() > 0) {
        blocks[id_a].push(blocks[id_b].top());
        blocks[id_b].pop();
    }
    return id_a;
}


// Combine new_block with the current list of blocks at vertex v until the sum of the new_block becomes positive
void combine_blocks(int v, block new_block) {
    while (blocks[v].size() > 0) {
        block top_block = blocks[v].top();
        if (new_block.sum <= 0) {
            blocks[v].pop();
            new_block = {max(new_block.requirement, top_block.requirement - new_block.sum), new_block.sum + top_block.sum};
        }
        else {
            // If sum is positive, we want to keep "requirement" sorted in non-decreasing order
            if (new_block.requirement > top_block.requirement) {
                blocks[v].pop();
                new_block = {new_block.requirement, new_block.sum + top_block.sum};
            }
            else {
                // new_block satisfies the requirements, push it to the list of the blocks at vertex v.
                blocks[v].push(new_block);
                break;
            }
        }
    }
    if (blocks[v].size() == 0) {
        blocks[v].push(new_block);
    }
    if (blocks[v].size() == 1 && blocks[v].top().sum <= 0) {
        blocks[v].pop();
    }
}


void dfs(int v) {
    if (children[v].size() == 0) {
        // For a new priority queue, set the graph child node as the 'leader' of the priority queue
        p_queue_index[v] = v;
    }
    for (int i = 0; i < children[v].size(); i++) {
        int a = children[v][i];
        dfs(a);
        if (i == 0) {
            p_queue_index[v] = p_queue_index[a];
        }
        else {
            // Merge priority queues of children vertices
            p_queue_index[v] = merge_priority_queues(p_queue_index[v], p_queue_index[a]);
        }
    }
    // Add block formed by vertex v to the list of merged blocks from children of v
    combine_blocks(p_queue_index[v], {max(0, -x[v]), x[v]});
}


int main() {
    int N;
    long long s, profit = 0;  // Profit starts from 0, and not from s.
    cin >> N >> s;
    for (int i = 1; i <= N; i++) {
        int p;
        cin >> x[i] >> p;
        children[p].push_back(i);
    }

    // Perform dfs which constructs the order of blocks to be visited independently on the s.
    dfs(0);

    // Once the block order is set, take all blocks that we can with the given value of s.
    while (blocks[p_queue_index[0]].size() > 0) {
        long long min_requirement = blocks[p_queue_index[0]].top().requirement;
        long long sum = blocks[p_queue_index[0]].top().sum;
        blocks[p_queue_index[0]].pop();
        if (s + profit >= min_requirement) {
            profit += sum;
        }
    }

    cout << profit << endl;
    return 0;
}

Compilation message (stderr)

Main.cpp: In function 'void dfs(int)':
Main.cpp:78:23: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   78 |     for (int i = 0; i < children[v].size(); i++) {
      |                     ~~^~~~~~~~~~~~~~~~~~~~
#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...