답안 #741438

# 제출 시각 아이디 문제 언어 결과 실행 시간 메모리
741438 2023-05-14T05:26:58 Z KoD Min-max tree (BOI18_minmaxtree) C++17
0 / 100
106 ms 23004 KB
// #define MULTEST

#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <chrono>
#include <cmath>
#include <complex>
#include <cstdio>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <limits>
#include <map>
#include <numeric>
#include <optional>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>

namespace kod {
namespace util {

template <class F> class FixedPoint : private F {
    constexpr FixedPoint(F&& f) noexcept : F(std::forward<F>(f)) {}
    template <class G> friend constexpr decltype(auto) make_fixed(G&&) noexcept;

  public:
    template <class... Args> constexpr decltype(auto) operator()(Args&&... args) const noexcept {
        return F::operator()(*this, std::forward<Args>(args)...);
    }
};

template <class G> [[nodiscard]] constexpr decltype(auto) make_fixed(G&& g) noexcept {
    using F = std::decay_t<G>;
    return FixedPoint<F>(std::forward<F>(g));
}

}  // namespace util
}  // namespace kod

namespace kod {
namespace util {

class ForwardLoop {
    int x, y;
    constexpr ForwardLoop(int x, int y) noexcept : x(x), y(y) {}
    friend constexpr ForwardLoop rep(int, int) noexcept;
    friend constexpr ForwardLoop rep(int) noexcept;

  public:
    constexpr ForwardLoop begin() const noexcept { return *this; }
    constexpr std::monostate end() const noexcept { return {}; }
    constexpr bool operator!=(std::monostate) const noexcept { return x < y; }
    constexpr void operator++() const noexcept {}
    constexpr int operator*() noexcept { return x++; }
};

[[nodiscard]] constexpr ForwardLoop rep(int l, int r) noexcept { return ForwardLoop(l, r); }
[[nodiscard]] constexpr ForwardLoop rep(int n) noexcept { return ForwardLoop(0, n); }

class BackwardLoop {
    int x, y;
    constexpr BackwardLoop(int x, int y) noexcept : x(x), y(y) {}
    friend constexpr BackwardLoop revrep(int, int) noexcept;
    friend constexpr BackwardLoop revrep(int) noexcept;

  public:
    constexpr BackwardLoop begin() const noexcept { return *this; }
    constexpr std::monostate end() const noexcept { return {}; }
    constexpr bool operator!=(std::monostate) const noexcept { return x > y; }
    constexpr void operator++() const noexcept {}
    constexpr int operator*() noexcept { return --x; }
};

[[nodiscard]] constexpr BackwardLoop revrep(int l, int r) noexcept { return BackwardLoop(r, l); }
[[nodiscard]] constexpr BackwardLoop revrep(int n) noexcept { return BackwardLoop(n, 0); }

template <class F> constexpr void repeat(int n, const F& f) noexcept {
    assert(n >= 0);
    while (n--) f();
}

}  // namespace util
}  // namespace kod

namespace kod {
namespace util {

namespace stdio_impl {

template <class T> T scan() {
    T x;
    std::cin >> x;
    return x;
}
struct scan_any {
    template <class T> operator T() const { return scan<T>(); }
};

}  // namespace stdio_impl

template <class T = void> decltype(auto) scan() {
    if constexpr (std::is_same_v<T, void>)
        return stdio_impl::scan_any{};
    else
        return stdio_impl::scan<T>();
}
template <class T, std::size_t N> std::array<T, N> scan_arr() {
    std::array<T, N> a;
    for (auto& x : a) x = scan<T>();
    return a;
}
template <class T> std::vector<T> scan_vec(int n) {
    if (n == -1) n = scan<int>();
    assert(n >= 0);
    std::vector<T> v;
    v.reserve(n);
    while (n--) v.push_back(scan<T>());
    return v;
}

void flush() { std::cout << std::flush; }
void print() {}
template <class T, class... Args> void print(const T& x, const Args&... args) {
    std::cout << x;
    if (sizeof...(args) != 0) std::cout << ' ';
    print(args...);
}
template <class... Args> void println(const Args&... args) {
    print(args...);
    std::cout << '\n';
}
template <class C> void print_seq(const C& c, const char* sep = " ", const char* end = "\n") {
    bool f = false;
    for (const auto& x : c) {
        if (f)
            std::cout << sep;
        else
            f = true;
        std::cout << x;
    }
    std::cout << end;
}

}  // namespace util
}  // namespace kod

namespace kod {
namespace sol {

using ll = long long;
using uint = unsigned;
using ull = unsigned long long;

using std::array;
using std::pair;
using std::string;
using std::tuple;
using std::vector;

using namespace util;

constexpr int inf = std::numeric_limits<int>::max() / 2;
constexpr ll infll = std::numeric_limits<ll>::max() / 2;

constexpr ll floor_div(ll x, ll y) noexcept {
    assert(y != 0);
    return x / y - ((x ^ y) < 0 && x % y != 0);
}
constexpr ll ceil_div(ll x, ll y) noexcept {
    assert(y != 0);
    return x / y + ((x ^ y) >= 0 && x % y != 0);
}

template <class T> constexpr bool setmin(T& lhs, const T& rhs) noexcept {
    if (lhs > rhs) {
        lhs = rhs;
        return true;
    }
    return false;
}
template <class T> constexpr bool setmax(T& lhs, const T& rhs) noexcept {
    if (lhs < rhs) {
        lhs = rhs;
        return true;
    }
    return false;
}

void run();

}  // namespace sol
}  // namespace kod

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout << std::fixed << std::setprecision(20);
    int cases = 1;
#ifdef MULTEST
    std::cin >> cases;
#endif
    while (cases--) kod::sol::run();
    return 0;
}

#ifdef KOD_LOCAL
#define OJ_LOCAL(a, b) b
#include <kodlib/misc/debug>
#else
#define OJ_LOCAL(a, b) a
#define DBG(...)
#define SHOW(...)
#endif

namespace kod {
namespace sol {

namespace proconlib {

template <class T> class SimpleQueue {
    std::vector<T> payload;
    int pos;

  public:
    SimpleQueue() : payload(), pos(0) {}
    explicit SimpleQueue(const int n) : SimpleQueue() { reserve(n); }

    int size() const { return (int)payload.size() - pos; }
    bool empty() const { return size() == 0; }
    T& front() { return payload[pos]; }

    void push(const T& t) { payload.push_back(t); }
    void push(T&& t) { payload.push_back(std::move(t)); }
    void pop() { pos++; }

    void reserve(int n) { payload.reserve(n); }
    void clear() {
        payload.clear();
        pos = 0;
    }
};

}  // namespace proconlib

class IndexOffset {
    int offset, len;

  public:
    constexpr IndexOffset() noexcept : offset(), len() {}
    explicit constexpr IndexOffset(const int o, const int l) noexcept : offset(o), len(l) {}
    constexpr int size() const { return len; }
    constexpr int operator[](const int i) const noexcept {
        assert(i < len);
        return offset + i;
    }
    constexpr int to_idx(const int i) const noexcept {
        assert(offset <= i and i < offset + len);
        return i - offset;
    }
};

template <class F> struct RecursiveLambda : private F {
    explicit constexpr RecursiveLambda(F&& f) : F(std::forward<F>(f)) {}
    template <class... Args> constexpr decltype(auto) operator()(Args&&... args) const {
        return F::operator()(*this, std::forward<Args>(args)...);
    }
};

template <class F> constexpr decltype(auto) rec_lambda(F&& f) {
    return RecursiveLambda<F>(std::forward<F>(f));
}

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

  public:
    explicit constexpr Range(const int first, const int last) noexcept
        : first(first), last(std::max(first, last)) {}
    constexpr Iter begin() const noexcept { return first; }
    constexpr Iter 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); }

template <class Flow, std::enable_if_t<std::is_integral_v<Flow>>* = nullptr> class Dinic {
  public:
    struct Edge {
        int src, dst;
        Flow flow, cap;
    };

  private:
    int node_count;
    std::vector<Edge> graph;

  public:
    Dinic() : node_count(0), graph() {}
    explicit Dinic(const int n) : node_count(n), graph() {}

    int size() const { return node_count; }
    int edge_count() const { return graph.size(); }

    int add_vertex() { return node_count++; }
    IndexOffset add_vertices(const int n) {
        assert(n >= 0);
        const IndexOffset ret(size(), n);
        node_count += n;
        return ret;
    }

    const Edge& get_edge(const int i) const {
        assert(0 <= i and i < edge_count());
        return graph[i];
    }
    int add_edge(const int src, const int dst, const Flow& cap) {
        assert(0 <= src and src < size());
        assert(0 <= dst and dst < size());
        assert(cap >= 0);
        graph.push_back(Edge{src, dst, 0, cap});
        return edge_count() - 1;
    }

    Flow flow(const int src, const int dst) {
        return flow(src, dst, std::numeric_limits<Flow>::max());
    }
    Flow flow(const int src, const int dst, const Flow& flow_limit) {
        assert(0 <= src and src < size());
        assert(0 <= dst and dst < size());
        assert(src != dst);
        const int n = size();
        const int m = edge_count();
        struct E {
            int dst, rev;
            Flow cap;
        };
        std::vector<E> edge(2 * m);
        std::vector<int> start(n + 1), eidx(m);
        {
            std::vector<int> deg(n), reidx(m);
            for (const int i : rep(m)) {
                eidx[i] = deg[graph[i].src]++;
                reidx[i] = deg[graph[i].dst]++;
            }
            for (const int i : rep(n)) start[i + 1] = start[i] + deg[i];
            for (const int i : rep(m)) {
                const auto& e = graph[i];
                const int u = e.src, v = e.dst;
                eidx[i] += start[u];
                reidx[i] += start[v];
                edge[eidx[i]] = {v, reidx[i], e.cap - e.flow};
                edge[reidx[i]] = {u, eidx[i], e.flow};
            }
        }
        std::vector<int> level(n), iter(n);
        proconlib::SimpleQueue<int> que;
        const auto bfs = [&] {
            std::fill(level.begin(), level.end(), n);
            level[src] = 0;
            while (!que.empty()) que.pop();
            que.push(src);
            while (!que.empty()) {
                const int u = que.front();
                que.pop();
                for (const int i : rep(start[u], start[u + 1])) {
                    const auto& e = edge[i];
                    if (e.cap == 0 or level[e.dst] < n) continue;
                    level[e.dst] = level[u] + 1;
                    if (e.dst == dst) return;
                    que.push(e.dst);
                }
            }
        };
        const auto dfs = rec_lambda([&](auto&& dfs, const int u, const Flow& ub) -> Flow {
            if (u == src) return ub;
            Flow ret = 0;
            for (int& i = iter[u]; i < start[u + 1]; i += 1) {
                auto& e = edge[i];
                auto& re = edge[e.rev];
                if (level[u] <= level[e.dst] or re.cap == 0) continue;
                const Flow d = dfs(e.dst, std::min(ub - ret, re.cap));
                if (d == 0) continue;
                e.cap += d;
                re.cap -= d;
                ret += d;
                if (ret == ub) return ret;
            }
            level[u] = n;
            return ret;
        });
        Flow ret = 0;
        while (ret < flow_limit) {
            bfs();
            if (level[dst] == n) break;
            std::copy(start.begin(), start.begin() + n, iter.begin());
            const Flow f = dfs(dst, flow_limit - ret);
            if (f == 0) break;
            ret += f;
        }
        for (const int i : rep(m)) graph[i].flow = graph[i].cap - edge[eidx[i]].cap;
        return ret;
    }

    std::vector<char> min_cut(const int src) const {
        assert(0 <= src and src < size());
        const int n = size();
        std::vector<std::vector<int>> adj(n);
        for (const auto& e : graph) {
            if (e.flow < e.cap) adj[e.src].push_back(e.dst);
            if (e.flow > 0) adj[e.dst].push_back(e.src);
        }
        std::vector<char> ret(n);
        proconlib::SimpleQueue<int> que;
        que.push(src);
        ret[src] = true;
        while (!que.empty()) {
            const int u = que.front();
            que.pop();
            for (const int v : adj[u]) {
                if (!ret[v]) {
                    ret[v] = true;
                    que.push(v);
                }
            }
        }
        return ret;
    }
};

class UnionFind {
  public:
    explicit UnionFind(int n) : par(n, -1) {}

    int find(int u) { return par[u] < 0 ? u : par[u] = find(par[u]); }

    void absorb(int u, int v) {
        u = find(u);
        v = find(v);
        if (u != v) {
            par[v] = u;
        }
    }

  private:
    vector<int> par;
};

void run() {
    const int N = scan();
    vector<vector<int>> G(N);
    for (const int i : rep(N - 1)) {
        const int a = scan<int>() - 1;
        const int b = scan<int>() - 1;
        G[a].push_back(b);
        G[b].push_back(a);
    }

    vector<int> par(N), dep(N);
    make_fixed([&](auto&& dfs, const int u) -> void {
        for (const int v : G[u]) {
            if (par[u] == v) continue;
            par[v] = u;
            dep[v] = dep[u] + 1;
            dfs(v);
        }
    })(0);

    const int M = scan();
    vector<int> val(N);
    vector<array<int, 4>> min, max;
    for (const int i : rep(M)) {
        const char c = scan();
        const int a = scan<int>() - 1;
        const int b = scan<int>() - 1;
        const int x = scan();
        val[i] = x;
        (c == 'm' ? min : max).push_back({x, a, b, i});
    }

    vector<int> lowb(N, -1);
    {
        UnionFind dsu(N);
        std::sort(min.rbegin(), min.rend());
        for (const auto& [x, a, b, i] : min) {
            int u = a, v = b;
            while (true) {
                u = dsu.find(u);
                v = dsu.find(v);
                if (dep[u] < dep[v]) std::swap(u, v);
                if (lowb[u] == -1) lowb[u] = i;
                if (u == v) break;
                dsu.absorb(par[u], u);
                u = par[u];
            }
        }
    }

    vector<int> uppb(N, -1);
    {
        UnionFind dsu(N);
        std::sort(max.begin(), max.end());
        for (const auto& [x, a, b, i] : max) {
            int u = a, v = b;
            while (true) {
                u = dsu.find(u);
                v = dsu.find(v);
                if (dep[u] < dep[v]) std::swap(u, v);
                if (uppb[u] == -1) uppb[u] = i;
                if (u == v) break;
                dsu.absorb(par[u], u);
                u = par[u];
            }
        }
    }

    Dinic<int> dinic;
    const auto node = dinic.add_vertices(N);
    const auto query = dinic.add_vertices(N);
    const int src = dinic.add_vertex();
    const int dst = dinic.add_vertex();
    for (const int i : rep(N)) {
        dinic.add_edge(src, node[i], 1);
    }
    for (const int i : rep(M)) {
        dinic.add_edge(query[i], dst, 1);
    }
    vector<int> eid;
    for (const int i : rep(1, N)) {
        if (lowb[i] != -1) {
            const int e = dinic.add_edge(node[i], query[lowb[i]], 1);
            eid.push_back(e);
        }
        if (uppb[i] != -1) {
            const int e = dinic.add_edge(node[i], query[uppb[i]], 1);
            eid.push_back(e);
        }
    }

    const int F = dinic.flow(src, dst);
    DBG(F);
    vector<int> ans(N);
    for (const int i : eid) {
        const auto& e = dinic.get_edge(i);
        if (e.flow == 1) {
            ans[node.to_idx(e.src)] = val[query.to_idx(e.dst)];
        }
    }
    for (const int i : rep(1, N)) {
        println(i + 1, par[i] + 1, ans[i]);
    }
}

}  // namespace sol
}  // namespace kod

Compilation message

minmaxtree.cpp: In function 'void kod::sol::run()':
minmaxtree.cpp:471:20: warning: unused variable 'i' [-Wunused-variable]
  471 |     for (const int i : rep(N - 1)) {
      |                    ^
minmaxtree.cpp:559:15: warning: unused variable 'F' [-Wunused-variable]
  559 |     const int F = dinic.flow(src, dst);
      |               ^
# 결과 실행 시간 메모리 Grader output
1 Incorrect 1 ms 212 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Incorrect 106 ms 23004 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Incorrect 72 ms 19008 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Incorrect 1 ms 212 KB Output isn't correct
2 Halted 0 ms 0 KB -