제출 #1329827

#제출 시각아이디문제언어결과실행 시간메모리
1329827model_codePPP (EGOI23_ppp)C++20
100 / 100
217 ms37576 KiB
#include <bits/stdc++.h>
using namespace std;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, M;
    cin >> N >> M;

    vector<int> x(M), y(M);
    // For each participant, list of matches they participate in (sorted by day)
    vector<vector<int>> matches(N);

    for(int i = 0; i < M; i++){
        cin >> x[i] >> y[i];
        matches[x[i]].push_back(i);
        matches[y[i]].push_back(i);
    }

    // Build tree: parent[i] = next match where winner x[i] participates, or M (fake root)
    // For each participant, we need a pointer to find the next match after a given one.
    // We can use upper_bound on the sorted matches list.
    vector<int> par(M);
    vector<vector<int>> children(M + 1); // M is the fake root

    for(int i = 0; i < M; i++){
        int w = x[i]; // winner of match i
        auto &ml = matches[w];
        // Find next match of w after day i
        auto it = upper_bound(ml.begin(), ml.end(), i);
        if(it == ml.end()){
            par[i] = M; // fake root
        } else {
            par[i] = *it;
        }
        children[par[i]].push_back(i);
    }

    // span[i] = par[i] - i (par[i] is either a day number or M)
    // When par[i] = M, span[i] = M - i
    // Otherwise span[i] = par[i] - i

    // DFS from fake root (node M)
    // Maintain cnt[p] for each participant p
    // Use a set<pair<int,int>> storing (-cnt, p) for efficient max query
    // (We only insert/remove entries with nonzero cnt)

    vector<int> cnt(N, 0);
    set<pair<int,int>> S; // (-cnt[p], p) for participants with cnt[p] > 0

    vector<int> medal_winner(M);

    // Iterative DFS to avoid stack overflow
    // We use a stack of (node, child_index, entered)
    // When we first visit a node, we "enter" it (add span to cnt)
    // Then we process its children one by one
    // When all children are done, we "leave" it (subtract span from cnt)

    // Actually, let's use a different iterative DFS approach:
    // Push (node, false) initially.
    // When popped with false: push (node, true), then push all children (child, false).
    // When popped with true: this is the "leave" step.
    // But we need to process the medal right after entering.

    // Better: explicit stack with state
    struct Frame {
        int node;
        int childIdx;
    };

    stack<Frame> stk;
    // Start from fake root's children
    // The fake root doesn't correspond to a match, so we handle it specially
    for(int c : children[M]){
        stk.push({c, -1}); // -1 means not yet entered
    }

    // We need to reverse the order so that children are processed in the right order
    // Actually, order doesn't matter for correctness

    // Hmm, the above won't work well because we push all root's children at once.
    // Let me use a cleaner iterative DFS.

    // Use a stack of (node, phase)
    // phase 0: enter (add span, process medal, then push children)
    // phase 1: leave (subtract span)

    stack<pair<int,int>> dfs_stack;
    for(int i = (int)children[M].size()-1; i >= 0; i--){
        dfs_stack.push({children[M][i], 0});
    }

    while(!dfs_stack.empty()){
        auto [node, phase] = dfs_stack.top();
        dfs_stack.pop();

        if(phase == 0){
            // Enter node
            int w = x[node];
            int span = par[node] - node;

            // Update cnt and set
            if(cnt[w] > 0){
                S.erase({-cnt[w], w});
            }
            cnt[w] += span;
            S.insert({-cnt[w], w});

            // Process medal for this node
            // The winner of medal 'node' is the participant with max cnt (smallest index on tie)
            auto it = S.begin();
            medal_winner[node] = it->second;

            // Push leave marker
            dfs_stack.push({node, 1});

            // Push children (in reverse order so they're processed in order)
            auto &ch = children[node];
            for(int i = (int)ch.size()-1; i >= 0; i--){
                dfs_stack.push({ch[i], 0});
            }
        } else {
            // Leave node
            int w = x[node];
            int span = par[node] - node;

            S.erase({-cnt[w], w});
            cnt[w] -= span;
            if(cnt[w] > 0){
                S.insert({-cnt[w], w});
            }
        }
    }

    // Count medals per participant
    vector<int> ans(N, 0);
    for(int i = 0; i < M; i++){
        ans[medal_winner[i]]++;
    }

    for(int i = 0; i < N; i++){
        cout << ans[i];
        if(i + 1 < N) cout << ' ';
    }
    cout << '\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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...