제출 #1268997

#제출 시각아이디문제언어결과실행 시간메모리
1268997hoa208다리 (APIO19_bridges)C++20
59 / 100
3095 ms5956 KiB
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
struct Edge { int u, v; int d; };
struct Query { int t, x, y; };

struct B {
    int u, v, d, id;
    bool operator < (const B &o) const {
        if (d != o.d) return d > o.d; // descending by d
        return id < o.id;
    }
};

int n, m, q;
vector<Edge> ed; // 1..m
vector<Query> qr; // 0..q-1

// DSU with rollback
vector<int> parent_, sz_;
vector<int> stk; // store v-roots that were attached

int findset_iter(int u) {
    while (parent_[u] != u) u = parent_[u];
    return u;
}

void unite_rb(int a, int b) {
    a = findset_iter(a);
    b = findset_iter(b);
    if (a == b) return;
    if (sz_[a] < sz_[b]) swap(a, b);
    // attach b under a
    parent_[b] = a;
    sz_[a] += sz_[b];
    stk.push_back(b);
}

void rollback_one() {
    int b = stk.back(); stk.pop_back();
    int a = parent_[b]; // a is current parent (the one we set)
    // decrement size of a, restore b as root
    sz_[a] -= sz_[b];
    parent_[b] = b;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
#if defined(LOCAL)
    freopen("input.txt","r",stdin);
#endif

    cin >> n >> m;
    ed.assign(m+1, {0,0,0});
    for (int i = 1; i <= m; ++i) {
        int u,v,d; cin >> u >> v >> d;
        ed[i] = {u,v,d};
    }
    cin >> q;
    qr.assign(q, {0,0,0});
    for (int i = 0; i < q; ++i) {
        int t,x,y; cin >> t >> x >> y;
        qr[i] = {t,x,y};
    }

    int BLOCK = max(1, (int)sqrt(q));
    vector<int> ans(q, 0);

    // process blocks
    for (int L = 0; L < q; L += BLOCK) {
        int R = min(q-1, L + BLOCK - 1);

        // gather changed edges in this block
        vector<char> is_changed(m+1, 0);
        vector<int> changedList;
        for (int i = L; i <= R; ++i) if (qr[i].t == 1) {
            int ei = qr[i].x;
            if (!is_changed[ei]) {
                is_changed[ei] = 1;
                changedList.push_back(ei);
            }
        }

        // curd simulates weights inside the block (start from current global ed)
        vector<int> curd(m+1);
        for (int i = 1; i <= m; ++i) curd[i] = ed[i].d;

        // vr_block: for each query in block store list of changed edges (indices) that at that query time have weight >= query.w
        int BQ = R - L + 1;
        vector<vector<int>> vr_block(BQ);

        // simulate queries in block sequentially to build vr_block and also apply updates to curd (and to global ed at the end of handling)
        for (int i = L; i <= R; ++i) {
            int idx = i - L;
            if (qr[i].t == 1) {
                int ei = qr[i].x, nw = qr[i].y;
                curd[ei] = nw;      // change current weight in block simulation
                ed[ei].d = nw;      // persist update globally (so next blocks see it)
            } else {
                int u = qr[i].x, w = qr[i].y;
                // for all changed edges, if current weight >= w, add to vr
                for (int eidx : changedList) {
                    if (curd[eidx] >= w) vr_block[idx].push_back(eidx);
                }
            }
        }

        // build vector b: all base edges (not changed in this block) + one entry per type2 query in block
        vector<B> b;
        b.reserve((m - (int)changedList.size()) + BQ);
        // add queries (type2) entries
        for (int i = L; i <= R; ++i) {
            if (qr[i].t == 2) {
                int u = qr[i].x, w = qr[i].y;
                b.push_back({u, 0, w, i}); // id stores global query index
            }
        }
        // add base edges (those not in changed set) with their current global ed[].d
        for (int i = 1; i <= m; ++i) {
            if (!is_changed[i]) {
                b.push_back({ed[i].u, ed[i].v, ed[i].d, -1});
            }
        }
        sort(b.begin(), b.end());

        // init DSU
        parent_.assign(n+1, 0);
        sz_.assign(n+1, 1);
        for (int i = 1; i <= n; ++i) parent_[i] = i;
        stk.clear();

        // process sorted b
        for (auto &item : b) {
            if (item.id == -1) {
                // base edge: union permanently for this block
                unite_rb(item.u, item.v);
            } else {
                // query: we need to union all changed edges listed in vr_block for this specific query (temporarily)
                int qidx = item.id; // global index
                int localIdx = qidx - L;
                int presz = (int)stk.size();
                for (int eidx : vr_block[localIdx]) {
                    unite_rb(ed[eidx].u, ed[eidx].v);
                }
                int root = findset_iter(item.u);
                ans[qidx] = sz_[root];
                // rollback the temporary unions (those we pushed from vr_block)
                while ((int)stk.size() > presz) rollback_one();
            }
        }

        // rollback all base unions to restore empty DSU for next block
        while (!stk.empty()) rollback_one();

        // vr_block and other per-block containers go out of scope / cleared automatically
    }

    // output answers for all type2 queries in order
    for (int i = 0; i < q; ++i) if (qr[i].t == 2) {
        cout << ans[i] << '\n';
    }
    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...