Submission #519451

#TimeUsernameProblemLanguageResultExecution timeMemory
519451CyanmondBridges (APIO19_bridges)C++17
30 / 100
3051 ms11956 KiB
#pragma GCC optimize ("O3")
#pragma GCC target ("avx2")

#line 1 "paper.cpp"
#include <bits/stdc++.h>

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

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

class RollbackUnionFind {
    std::vector<int> data;
    std::stack<std::pair<int, int>> history;

  public:
    explicit RollbackUnionFind(const int n_) : data(n_, -1) {}

    int size() const noexcept {
        return len(data);
    }

    int get_state() const {
        return len(history) / 2;
    }

    int leader(int v) const {
        assert(0 <= v and v < size());
        while (data[v] >= 0) {
            v = data[v];
        }
        return v;
    }

    int size(const int v) const {
        assert(0 <= v and v < size());
        return -data[leader(v)];
    }

    bool is_same(const int x, const int y) const {
        return leader(x) == leader(y);
    }

    bool unite(int x, int y) {
        assert(0 <= x and x < size());
        assert(0 <= y and y < size());
        x = leader(x);
        y = leader(y);
        if (x == y) {
            return false;
        }
        if (data[x] > data[y]) {
            std::swap(x, y);
        }
        history.emplace(x, data[x]);
        history.emplace(y, data[y]);
        data[x] += data[y];
        data[y] = x;
        return true;
    }

    int root_press(int v) {
        if (data[v] >= 0) {
            return data[v] = root_press(data[v]);
        } else {
            return v;
        }
    }

    void undo() {
        assert(not history.empty());
        data[history.top().first] = history.top().second;
        history.pop();
        data[history.top().first] = history.top().second;
        history.pop();
    }

    void rollback(int steps) {
        assert(0 <= steps and 2 * steps <= len(history));
        while (steps != 0) {
            --steps;
            undo();
        }
    }
};
#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/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 3 "library2/utility/scan.hpp"

template <typename T = int> T scan() {
    T ret;
    std::cin >> ret;
    return ret;
}
#line 5 "library2/utility/upb.hpp"

template <class Container, class T> constexpr int upb(const Container &c, const T &val) {
    return static_cast<int>(std::distance(c.cbegin(), std::upper_bound(c.cbegin(), c.cend(), val)));
}
#line 9 "paper.cpp"

int main() {
    const int N = scan();
    const int M = scan();
    std::vector<int> U(M), V(M), D(M);
    for (const int i : rep(M)) {
        U[i] = scan() - 1;
        V[i] = scan() - 1;
        D[i] = scan();
    }
    const int Q = scan();
    std::vector<int> T(Q), A(Q), B(Q);
    for (const int i : rep(Q)) {
        T[i] = scan();
        A[i] = scan() - 1;
        B[i] = scan();
    }

    std::vector<int> answer(Q);

    auto solve_sub = [&](const int l, const int r, std::vector<int> &F) {
        assert(len(F) == M);
        assert(0 <= l and l <= r and r <= Q);

        std::vector<bool> is_changed(M);
        std::vector<std::vector<std::pair<int, int>>> history(M);
        for (const int i : rep(M)) {
            history[i].push_back({-1, F[i]});
        }

        for (const int i : rep(l, r)) {
            if (T[i] == 1) {
                is_changed[A[i]] = true;
                history[A[i]].push_back({i, B[i]});
                F[A[i]] = B[i];
            }
        }

        RollbackUnionFind uft(N);

        std::vector<int> edges;
        for (const int i : rep(M)) {
            if (not is_changed[i]) {
                edges.push_back(i);
            }
        }
        std::sort(edges.begin(), edges.end(),
                  [&](const int a, const int b) { return F[a] > F[b]; });

        std::vector<int> queries;
        for (const int i : rep(l, r)) {
            if (T[i] == 2) {
                queries.push_back(i);
            }
        }
        std::sort(queries.begin(), queries.end(),
                  [&](const int a, const int b) { return B[a] > B[b]; });

        int idx = 0;

        for (const int x : queries) {
            while (idx != len(edges) and F[edges[idx]] >= B[x]) {
                uft.unite(U[edges[idx]], V[edges[idx]]);
                uft.root_press(U[edges[idx]]);
                uft.root_press(V[edges[idx]]);
                ++idx;
            }

            int count_back = 0;
            for (const int i : rep(l, r)) {
                if (T[i] == 1) {
                    const int p = upb(history[A[i]], std::make_pair(x, 0));
                    if (history[A[i]][p - 1].second >= B[x]) {
                        if (uft.unite(U[A[i]], V[A[i]])) {
                            ++count_back;
                        }
                    }
                }
            }

            answer[x] = uft.size(A[x]);
            uft.rollback(count_back);
        }
    };

    constexpr int block_size = 300;

    for (int i = 0; i < Q; i += block_size) {
        solve_sub(i, std::min(i + block_size, Q), D);
    }

    for (const auto e : answer) {
        if (e != 0) {
            std::cout << e << std::endl;
        }
    }
}
#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...