Submission #1222073

#TimeUsernameProblemLanguageResultExecution timeMemory
1222073totoroThousands Islands (IOI22_islands)C++20
11.90 / 100
29 ms13896 KiB
#include "islands.h"

#include <iostream>
#include <map>
#include <variant>
#include <vector>

std::variant<bool, std::vector<int>> find_journey_connected(int N, int M, std::vector<int> U, std::vector<int> V, std::vector<int> original_labels);

std::variant<bool, std::vector<int>> find_journey(int N, int M, std::vector<int> U, std::vector<int> V) {
    std::vector<std::vector<int>> canoesfrom(N);
    for (int i = 0; i < M; ++i) canoesfrom[U[i]].push_back(i);
    std::vector<bool> seen(N);

    std::vector<int> stack = {0};
    while (!stack.empty()) {
        int node = stack.back();
        stack.pop_back();
        if (seen[node]) continue;
        seen[node] = true;
        for (int i : canoesfrom[node]) {
            stack.push_back(V[i]);
        }
    }

    std::vector<int> newu, newv, original_labels;
    int newm = 0;
    for (int i = 0; i < N; ++i) {
        if (!seen[i]) continue;
        for (int out : canoesfrom[i]) {
            newu.push_back(U[out]);
            newv.push_back(V[out]);
            original_labels.push_back(out);
            ++newm;
        }
    }
    return find_journey_connected(N, newm, newu, newv, original_labels);
}

std::variant<bool, std::vector<int>> find_journey_connected(int N, int M, std::vector<int> U, std::vector<int> V, std::vector<int> original_labels) {
    std::vector<std::vector<int>> out(N);
    for (int i = 0; i < M; ++i) out[U[i]].push_back(i);
    U.push_back(-1);
    V.push_back(0);  // dummy edge to source

    // stage 1: find any loop
    std::vector<int> is_marked(N);
    std::vector<int> seen(N);
    std::vector<int> inpath(N);
    std::vector<int> path;
    std::vector<int> stack = {M};
    bool foundcyclestagei = false;
    while (!stack.empty()) {
        int canoe = stack.back();
        stack.pop_back();
        if (canoe == -1) {
            inpath[V[path.back()]] = false;
            path.pop_back();
            continue;
        }
        path.push_back(canoe);
        int node = V[canoe];
        if (seen[node]) {
            if (!inpath[node]) continue;
            foundcyclestagei = true;
            is_marked[node] = true;
            while (U[path.back()] != node) {
                is_marked[U[path.back()]] = true;
                path.pop_back();
            }
            path.pop_back();
            break;
        }
        seen[node] = true;
        inpath[node] = true;
        for (int to : out[node]) {
            stack.push_back(-1);
            stack.push_back(to);
        }
    }
    if (!foundcyclestagei) return false;

    // Stage 2: check multiple reachability to marked nodes
    std::vector<int> memo(N, -1);
    auto check = [&](int node, auto check) -> bool {
        if (memo[node] != -1) return memo[node];
        if (is_marked[node]) return true;
        memo[node] = false;
        for (int to : out[node]) {
            memo[node] |= check(V[to], check);
        }
        for (int to : out[node]) {
            memo[node] |= check(V[to], check);
        }
        return memo[node];
    };
    bool multiplereachabilitystageii = false;
    for (int i = 0; i < N; ++i) {
        if (is_marked[i] && i != V[path.back()]) continue;
        int canoecnt = 0;
        for (int to : out[i]) {
            canoecnt += check(V[to], check);
        }
        multiplereachabilitystageii |= (canoecnt >= 2);
    }
    if (multiplereachabilitystageii) return true;

    // Stage 3: we don't have multiple reachability, but let's look for a second cycle
    bool foundcyclestageiii = false;
    stack = {M};
    seen = std::vector<int>(N, false);
    while (!stack.empty()) {
        int canoe = stack.back();
        stack.pop_back();
        int node = V[canoe];
        if (is_marked[node] && node != path.back()) continue;  // avoid refinding the same cycle
        if (seen[node]) {
            foundcyclestageiii = true;
            break;
        }
        seen[node] = true;
        for (int to : out[node]) {
            stack.push_back(to);
        }
    }

    return foundcyclestageiii;
}
#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...