제출 #393694

#제출 시각아이디문제언어결과실행 시간메모리
393694palilo다리 (APIO19_bridges)C++17
0 / 100
2597 ms4520 KiB
#include <bits/stdc++.h>
using namespace std;

struct edge {
    int u, v, w;
};

struct disjoint_set {
    vector<int> par;
    vector<pair<int, int>> stk;

    disjoint_set(int n) : par(n, -1) {}

    void clear() {
        fill(par.begin(), par.end(), -1);
        stk.clear();
    }
    int find(int u) {
        while (par[u] >= 0) u = par[u];
        return u;
    }
    int get_size(int u) {
        return -par[find(u)];
    }
    bool merge(int u, int v, bool record) {
        u = find(u), v = find(v);
        if (u == v) return false;

        if (par[u] > par[v]) swap(u, v);
        if (record) stk.emplace_back(v, par[v]);
        par[u] += par[v];
        par[v] = u;
        return true;
    }
    void roll_back(size_t check_point) {
        for (; stk.size() != check_point; stk.pop_back()) {
            const auto& [u, sz] = stk.back();
            par[par[u]] -= sz, par[u] = sz;
        }
    }
};

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
#ifdef home
    freopen("in", "r", stdin);
    freopen("out", "w", stdout);
#endif
    int n, m;
    cin >> n >> m;

    vector<edge> e(m);
    for (auto& [u, v, w] : e)
        cin >> u >> v >> w, --u, --v;

    int q;
    cin >> q;

    vector<char> qtype(q);
    vector<pair<int, int>> query(q);
    for (int i = 0; i < q; ++i)
        cin >> qtype[i] >> query[i].first >> query[i].second, --query[i].first;

    // first = vertex_id or edge_id,    second = weight
    // first번 다리의 무게 제한 second로 바꿈
    // first에서 무게가 second인 차량이 갈 수 있는 섬 개수?

    const int BUCKET_SIZE = sqrt(q - 1) + 1;

    disjoint_set dsu(n);

    vector<bool> updated(m);
    vector<int> eid(m);
    iota(eid.begin(), eid.end(), 0);

    for (int l = 0; l < q; l += BUCKET_SIZE) {
        const int r = min(q, l + BUCKET_SIZE);
        // [l, r)에서 값이 변경되지 않은 다리는 그냥 그대로 사용.
        //                변경된 다리는 직접 구해줌.

        dsu.clear();
        fill(updated.begin(), updated.end(), false);

        for (int i = l; i < r; ++i)
            if (qtype[i] == '1')
                updated[query[i].first] = true;

        // [0, pivot) = updated edge's id
        int pivot = partition(eid.begin(), eid.end(), [&](auto& x) {
            return updated[x];
        }) - eid.begin();

        vector<pair<int, vector<int>>> print_query;
        for (int i = l; i < r; ++i)
            if (qtype[i] == '1')
                e[query[i].first].w = query[i].second;
            else {
                vector<int> check_list;
                for (int j = 0; j < pivot; ++j)
                    if (e[eid[j]].w >= query[i].second)
                        check_list.emplace_back(eid[j]);
                print_query.emplace_back(i, check_list);
            }

        sort(eid.begin() + pivot, eid.end(), [&](auto& a, auto& b) {
            return e[a].w > e[b].w;
        });
        sort(print_query.begin(), print_query.end(), [&](auto& a, auto& b) {
            return a.first > b.first;
        });

        for (const auto& [qi, check_list] : print_query) {
            for (; pivot < m && e[eid[pivot]].w >= query[qi].second; ++pivot)
                dsu.merge(e[eid[pivot]].u, e[eid[pivot]].v, false);

            auto check_point = dsu.stk.size();
            for (const auto& ei : check_list)
                dsu.merge(e[ei].u, e[ei].v, true);

            query[qi].first = dsu.get_size(query[qi].first);
            dsu.roll_back(check_point);
        }
    }

    for (int i = 0; i < q; ++i)
        if (qtype[i] == '2')
            cout << query[i].first << '\n';
}
#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...