Submission #522571

#TimeUsernameProblemLanguageResultExecution timeMemory
522571CyanmondSwapping Cities (APIO20_swap)C++17
100 / 100
671 ms43760 KiB
#line 1 "paper.cpp"
#include <bits/stdc++.h>

#line 3 "library2/utility/int_alias.hpp"

using i8 = std::int8_t;
using u8 = std::uint8_t;
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
#line 3 "library2/utility/len.hpp"

template <class Container> int len(const Container&c){
    return static_cast<int>(std::size(c));
}
#line 6 "library2/utility/priority_sort.hpp"

namespace magic {
template <class T, class... Tail>
void priority_sort_renumber(const std::vector<int> &order, std::vector<T> &head, Tail &...tail) {
    const int n = len(order);
    std::vector<T> sorted_head(n);
    for (int i = 0; i < n; ++i) {
        sorted_head[i] = head[order[i]];
    }
    head = std::move(sorted_head);
    if constexpr (sizeof...(Tail) != 0) {
        priority_sort_renumber(order, tail...);
    }
}
} // namespace magic

template <class Head, class... Tail>
std::vector<int> priority_sort(std::vector<Head> &head, std::vector<Tail> &...tail) {
    const int n = len(head);

    std::vector<std::tuple<Head, Tail..., int>> res(n);
    for (int i = 0; i < n; ++i) {
        res[i] = std::make_tuple(head[i], tail[i]..., i);
    }
    std::sort(res.begin(), res.end());

    std::vector<int> order(n);
    for (int i = 0; i < n; ++i) {
        order[i] = std::get<std::tuple_size_v<std::tuple<Head, Tail...>>>(res[i]);
    }
    magic::priority_sort_renumber(order, head, tail...);
    return order;
}
#line 3 "library2/utility/rep.hpp"

class Range {
    struct Iterator {
        int itr;
        constexpr Iterator(const int pos) noexcept : itr(pos) {}
        constexpr void operator++() noexcept {
            ++itr;
        }
        constexpr bool operator!=(const Iterator &other) const noexcept {
            return itr != other.itr;
        }
        constexpr int operator*() const noexcept {
            return itr;
        }
    };
    const Iterator first, last;

  public:
    explicit constexpr Range(const int f, const int l) noexcept
        : first(f), last(std::max(f, l)) {}
    constexpr Iterator begin() const noexcept {
        return first;
    }
    constexpr Iterator end() const noexcept {
        return last;
    }
};

constexpr Range rep(const int l, const int r) noexcept {
    return Range(l, r);
}
constexpr Range rep(const int n) noexcept {
    return Range(0, n);
}
#line 6 "paper.cpp"

class BubunEizokuUnionFindKaizou {
    int n;
    struct Node {
        int parent;
        int size;
        int deg1;
        int deg2;
        int deg3;
        bool cycle;
    };

    std::vector<Node> now_data;
    std::vector<i64> last_time;
    std::vector<std::vector<std::pair<i64, Node>>> history;
    std::vector<int> degree;
    std::vector<std::vector<std::pair<i64, int>>> deg_history;

  public:
    BubunEizokuUnionFindKaizou() = default;
    BubunEizokuUnionFindKaizou(const int n_) : n(n_) {
        now_data.resize(n);
        history.resize(n);
        for (const int i : rep(n)) {
            now_data[i] = {i, 1, 0, 0};
            history[i].push_back({0, {i, 1, 0, 0, 0, false}});
        }
        degree.assign(n, 0);
        last_time.assign(n, -1);
        deg_history.resize(n);
        for (const int i : rep(n)) {
            deg_history[i].push_back({0, 0});
        }
    }

    bool same(int a, int b, i64 t) {
        return root(a, t) == root(b, t);
    }

    int root(int v, i64 t) {
        if (last_time[v] == -1 or t < last_time[v]) {
            return v;
        } else {
            return root(now_data[v].parent, t);
        }
    }

    void unite(int a, int b, i64 c) {
        int ra = root(a, c), rb = root(b, c);
        if (ra == rb) {
            now_data[ra].cycle = true;
            if (degree[a] <= 3) {
                if (degree[a] == 0) {
                    ++now_data[ra].deg1;
                }
                if (degree[a] == 1) {
                    --now_data[ra].deg1;
                    ++now_data[ra].deg2;
                }
                if (degree[a] == 2) {
                    --now_data[ra].deg2;
                    ++now_data[ra].deg3;
                }
                if (degree[a] == 3) {
                    --now_data[ra].deg3;
                }
            }
            if (degree[b] <= 3) {
                if (degree[b] == 0) {
                    ++now_data[ra].deg1;
                }
                if (degree[b] == 1) {
                    --now_data[ra].deg1;
                    ++now_data[ra].deg2;
                }
                if (degree[b] == 2) {
                    --now_data[ra].deg2;
                    ++now_data[ra].deg3;
                }
            }
            ++degree[a];
            ++degree[b];
            history[ra].push_back({c, now_data[ra]});
        } else {
            if (now_data[ra].size < now_data[rb].size) {
                std::swap(a, b);
                std::swap(ra, rb);
            }
            now_data[ra].size += now_data[rb].size;
            now_data[rb].parent = ra;
            now_data[ra].deg1 += now_data[rb].deg1;
            now_data[ra].deg2 += now_data[rb].deg2;
            now_data[ra].deg3 += now_data[rb].deg3;
            now_data[ra].cycle |= now_data[rb].cycle;
            last_time[rb] = c;
            if (degree[a] <= 2) {
                if (degree[a] == 0) {
                    ++now_data[ra].deg1;
                }
                if (degree[a] == 1) {
                    --now_data[ra].deg1;
                    ++now_data[ra].deg2;
                }
                if (degree[a] == 2) {
                    --now_data[ra].deg2;
                    ++now_data[ra].deg3;
                }
            }
            if (degree[b] <= 2) {
                if (degree[b] == 0) {
                    ++now_data[ra].deg1;
                }
                if (degree[b] == 1) {
                    --now_data[ra].deg1;
                    ++now_data[ra].deg2;
                }
                if (degree[b] == 2) {
                    --now_data[ra].deg2;
                    ++now_data[ra].deg3;
                }
            }
            ++degree[a];
            ++degree[b];
            deg_history[a].push_back({c, degree[a]});
            deg_history[b].push_back({c, degree[b]});
            history[ra].push_back({c, now_data[ra]});
        }
    }

    int deg(int v, i64 t) {
        return (--std::upper_bound(deg_history[v].begin(), deg_history[v].end(),
                                   std::make_pair(t, 1000000001)))
            ->second;
    }

    Node view(int v, i64 t) {
        v = root(v, t);
        return (--std::upper_bound(history[v].begin(), history[v].end(), std::make_pair(t, 0),
                                   [](auto a, auto b) { return a.first < b.first; }))
            ->second;
    }
};

int N, M;
std::vector<int> U, V, W;
BubunEizokuUnionFindKaizou uft;

void init(int n, int m, std::vector<int> u, std::vector<int> v, std::vector<int> w) {
    N = n;
    M = m;
    U = u;
    V = v;
    W = w;
    uft = BubunEizokuUnionFindKaizou(N);
    priority_sort(W, U, V);
    for (const int i : rep(M)) {
        uft.unite(U[i], V[i], W[i]);
    }
}

int getMinimumFuelCapacity(int X, int Y) {
    if (not uft.same(X, Y, 1000000001)) {
        return -1;
    }
    const auto bestnode = uft.view(X, 1000000001);
    if ((not bestnode.cycle) and (bestnode.deg3 == 0)) {
        return -1;
    }
    int ok = 1000000001, ng = -1;
    while (ok - ng > 1) {
        const auto mid = (ok + ng) / 2;
        if (not uft.same(X, Y, mid)) {
            ng = mid;
        } else {
            const auto node = uft.view(X, mid);
            if ((not node.cycle) and (node.deg3 == 0)) {
                ng = mid;
            } else {
                ok = mid;
            }
        }
    }
    return ok;
}

/*
int main() {
    int N, M;
    assert(2 == scanf("%d %d", &N, &M));

    std::vector<int> U(M), V(M), W(M);
    for (int i = 0; i < M; ++i) {
        assert(3 == scanf("%d %d %d", &U[i], &V[i], &W[i]));
    }

    int Q;
    assert(1 == scanf("%d", &Q));

    std::vector<int> X(Q), Y(Q);
    for (int i = 0; i < Q; ++i) {
        assert(2 == scanf("%d %d", &X[i], &Y[i]));
    }

    init(N, M, U, V, W);

    std::vector<int> minimum_fuel_capacities(Q);
    for (int i = 0; i < Q; ++i) {
        minimum_fuel_capacities[i] = getMinimumFuelCapacity(X[i], Y[i]);
    }

    for (int i = 0; i < Q; ++i) {
        printf("%d\n", minimum_fuel_capacities[i]);
    }

    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...