Submission #1357052

#TimeUsernameProblemLanguageResultExecution timeMemory
1357052yogesh_saneLaser Strike (EGOI25_laserstrike)C++20
100 / 100
4 ms484 KiB
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

// Using XOR sum is actually necessary for the memory/speed constraints 
// and to mirror the original logic exactly, but I'll name it clearly.
struct Node {
    ll neighbor_xor_sum = 0;
    ll degree = 0;
};

void run_ann(ll n) {
    vector<Node> tree(n);
    for (int i = 0; i < n - 1; i++) {
        ll u, v; cin >> u >> v;
        tree[u].degree++; tree[v].degree++;
        tree[u].neighbor_xor_sum ^= v;
        tree[v].neighbor_xor_sum ^= u;
    }

    // leaf_pool[u] stores all leaves currently attached to node u
    vector<vector<ll>> leaf_pool(n);
    for (int i = 0; i < n; i++) {
        if (tree[i].degree == 1) {
            leaf_pool[tree[i].neighbor_xor_sum].push_back(i);
        }
    }

    // A and B help decide the 1-bit message by looking at the FIRST leaf of each neighbor
    vector<pair<ll, ll>> typeA, typeB;
    for (int i = 0; i < n; i++) {
        if (!leaf_pool[i].empty()) {
            if (i < leaf_pool[i][0]) typeA.push_back({i, leaf_pool[i][0]});
            else typeB.push_back({leaf_pool[i][0], i});
        }
    }

    sort(typeA.begin(), typeA.end());
    sort(typeB.begin(), typeB.end());

    // This specific flag logic ensures Kathrin knows how to handle the start
    bool flag = (typeB.empty() || (!typeA.empty() && typeA.back() > typeB[0]));
    cout << (flag ? 1 : 0) << endl;

    queue<ll> newly_formed_leaves;

    auto process_leaf_removal = [&](ll leaf, ll neighbor) {
        cout << leaf << endl;
        tree[leaf].degree--;
        tree[neighbor].degree--;
        tree[neighbor].neighbor_xor_sum ^= leaf;
        
        // If the neighbor becomes a leaf, it's ready to be processed later
        if (tree[neighbor].degree == 1) {
            newly_formed_leaves.push(neighbor);
            leaf_pool[tree[neighbor].neighbor_xor_sum].push_back(neighbor);
        }
    };

    auto clear_neighbor_leaves = [&](ll neighbor) {
        for (ll leaf : leaf_pool[neighbor]) {
            process_leaf_removal(leaf, neighbor);
        }
        leaf_pool[neighbor].clear();
    };

    // The order of execution here is CRITICAL for the 1-bit communication
    if (flag) for (auto& p : typeA) clear_neighbor_leaves(p.first);
    for (auto& p : typeB) clear_neighbor_leaves(p.second);
    if (!flag) for (auto& p : typeA) clear_neighbor_leaves(p.first);

    while (!newly_formed_leaves.empty()) {
        ll leaf = newly_formed_leaves.front();
        newly_formed_leaves.pop();
        if (tree[leaf].degree != 0) {
            clear_neighbor_leaves(tree[leaf].neighbor_xor_sum);
        }
    }
}

void run_kathrin(ll n) {
    string bit_msg; cin >> bit_msg;
    bool flag = (bit_msg[0] == '1');
    
    vector<ll> last_seen_at(n, 0);
    pair<ll, ll> reference_edge = {-1, -1};
    ll timer = 1;

    for (int i = 0; i < n - 1; i++) {
        ll a, b; cin >> a >> b;
        bool pick_b;

        if (last_seen_at[a] == 0 && last_seen_at[b] == 0) {
            // The logic for the "First Contact"
            pair<ll, ll> current = {min(a, b), max(a, b)};
            if (reference_edge.first != -1 && current < reference_edge) {
                flag = !flag; // Toggle flag if the order of edges is inverted
            }
            reference_edge = current;
            pick_b = flag;
        } else {
            // The "Recency" rule: pick the node we haven't just seen
            // If last_seen_at[a] == timer, a was the neighbor in the previous step
            pick_b = (last_seen_at[a] == timer || (last_seen_at[a] < last_seen_at[b] && last_seen_at[b] < timer));
        }

        cout << (pick_b ? b : a) << endl;
        last_seen_at[a] = last_seen_at[b] = ++timer;
    }
}

int main() {
    ios::sync_with_stdio(0); cin.tie(0);
    int p; ll n; cin >> p >> n;
    if (p == 1) run_ann(n);
    else run_kathrin(n);
    return 0;
}
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...