Submission #1311862

#TimeUsernameProblemLanguageResultExecution timeMemory
1311862nikaa123Simurgh (IOI17_simurgh)C++20
0 / 100
1 ms340 KiB
#include "simurgh.h"
#include <bits/stdc++.h>

using namespace std;

static int edge_status[300005]; 
static vector<pair<int, int>> graph_adj[505];
static int dpt[505], par_node[505], par_edge[505];
static bool vis[505];
static vector<int> t_edges;
static bool is_tree_edge[300005];

struct DSU_Structure {
    vector<int> p;
    DSU_Structure(int n) { p.resize(n); iota(p.begin(), p.end(), 0); }
    int find(int i) { return (p[i] == i) ? i : (p[i] = find(p[i])); }
    bool unite(int i, int j) {
        int root_i = find(i), root_j = find(j);
        if (root_i != root_j) { p[root_i] = root_j; return true; }
        return false;
    }
};

void run_dfs(int u, int p, int d) {
    vis[u] = true; dpt[u] = d;
    for (auto &edge : graph_adj[u]) {
        int v = edge.first, id = edge.second;
        if (v == p) continue;
        if (!vis[v]) {
            par_node[v] = u; par_edge[v] = id;
            t_edges.push_back(id); is_tree_edge[id] = true;
            run_dfs(v, u, d + 1);
        }
    }
}

void identify_tree_edges(int n, const vector<int>& u, const vector<int>& v) {
    for (int i = 0; i < (int)u.size(); i++) {
        if (is_tree_edge[i] || edge_status[i] != -1) continue;
        vector<int> cycle;
        int x = u[i], y = v[i];
        while (x != y) {
            if (dpt[x] > dpt[y]) { cycle.push_back(par_edge[x]); x = par_node[x]; }
            else { cycle.push_back(par_edge[y]); y = par_node[y]; }
        }
        cycle.push_back(i); // Back-edge is last

        int ref_idx = -1;
        for (int j = 0; j < (int)cycle.size(); j++) if (edge_status[cycle[j]] != -1) ref_idx = j;

        vector<int> res(cycle.size(), -1);
        int mx = -1, mn = 1e9;
        for (int j = 0; j < (int)cycle.size(); j++) {
            if (ref_idx != -1 && edge_status[cycle[j]] != -1 && j != ref_idx) continue;
            vector<int> q;
            for (int te : t_edges) {
                bool in_c = false;
                for (int ce : cycle) if (ce == te) in_c = true;
                if (!in_c) q.push_back(te);
            }
            for (int k = 0; k < (int)cycle.size() - 1; k++) if (k != j) q.push_back(cycle[k]);
            if (j != (int)cycle.size() - 1) q.push_back(i);
            res[j] = count_common_roads(q);
            mx = max(mx, res[j]); mn = min(mn, res[j]);
        }

        for (int j = 0; j < (int)cycle.size(); j++) {
            if (res[j] == -1) continue;
            if (mx == mn) edge_status[cycle[j]] = 0;
            else {
                // In a cycle, the edge causing the MIN result is the Royal road.
                edge_status[cycle[j]] = (res[j] == mn ? 1 : 0);
            }
        }
    }
    for (int te : t_edges) if (edge_status[te] == -1) edge_status[te] = 1;
}

vector<int> find_roads(int n, vector<int> u, vector<int> v) {
    int m = u.size(); t_edges.clear();
    for (int i = 0; i < n; i++) { graph_adj[i].clear(); vis[i] = false; }
    for (int i = 0; i < m; i++) {
        graph_adj[u[i]].push_back({v[i], i}); graph_adj[v[i]].push_back({u[i], i});
        edge_status[i] = -1; is_tree_edge[i] = false;
    }
    run_dfs(0, -1, 0);
    identify_tree_edges(n, u, v);

    for (int i = 0; i < n; i++) {
        vector<int> unknowns;
        for (auto &e : graph_adj[i]) {
            int id = e.second;
            if (i < (u[id] == i ? v[id] : u[id]) && edge_status[id] == -1) unknowns.push_back(id);
        }

        auto binary_solve = [&](auto self, vector<int> cand) -> void {
            if (cand.empty()) return;
            DSU_Structure dsu(n);
            vector<int> q;
            for (int id : cand) if (dsu.unite(u[id], v[id])) q.push_back(id);
            
            int tree_royals = 0;
            for (int te : t_edges) {
                if (dsu.unite(u[te], v[te])) {
                    q.push_back(te);
                    if (edge_status[te] == 1) tree_royals++;
                }
            }
            
            int found = count_common_roads(q) - tree_royals;
            if (found == 0) { for (int id : cand) edge_status[id] = 0; }
            else if (found == (int)cand.size()) { for (int id : cand) edge_status[id] = 1; }
            else {
                int mid = cand.size() / 2;
                self(self, vector<int>(cand.begin(), cand.begin() + mid));
                self(self, vector<int>(cand.begin() + mid, cand.end()));
            }
        };
        binary_solve(binary_solve, unknowns);
    }

    vector<int> final_set;
    for (int i = 0; i < m; i++) if (edge_status[i] == 1) final_set.push_back(i);
    return final_set;
}
#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...