Submission #699769

#TimeUsernameProblemLanguageResultExecution timeMemory
699769badontBridges (APIO19_bridges)C++17
0 / 100
3077 ms9908 KiB
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
#include <cmath>
#include <utility>
#include <array>
#include <numeric>
#include <list>
#include <iomanip>
using namespace std;


template<typename T, typename = void> struct is_iterable : false_type {};
template<typename T> struct is_iterable<T, void_t<decltype(begin(declval<T>())),decltype(end(declval<T>()))>> : true_type {};
template<typename T> typename enable_if<is_iterable<T>::value&&!is_same<T, string>::value,ostream&>::type operator<<(ostream &cout, T const &v);
template<typename A, typename B> ostream& operator<<(ostream &cout, pair<A, B> const &p) { return cout << "(" << p.f << ", " << p.s << ")"; }
template<typename T> typename enable_if<is_iterable<T>::value&&!is_same<T, string>::value,ostream&>::type operator<<(ostream &cout, T const &v) {
	cout << "["; 
	for (auto it = v.begin(); it != v.end();) {
		cout << *it;
		if (++it != v.end()) cout << ", ";
	}
	return cout << "]";
}
void dbg_out() { cout << endl; }
template<typename Head, typename... Tail> void dbg_out(Head H, Tail... T) { cout << ' ' << H; dbg_out(T...); }
#ifdef LOCAL
#define debug(...) cout << "(" << #__VA_ARGS__ << "):", dbg_out(__VA_ARGS__)
#else
#define debug(...) "zzz"
#endif

#define all(x) x.begin(),x.end()
#define pb push_back
using ll = long long;
using pii = pair<ll,ll>;
using ld = long double;

struct dsu_rollback {
    int n;
    vector<int> parent, changes, siz;

    dsu_rollback(int n) : n(n), parent(n), changes({}), siz(n, 1) {
        iota(all(parent),0);
    };

    int find(int g) {
        while (g != parent[g]) g = parent[g];
        return g;
    };

    void onion(int a, int b) {
        a = find(a), b = find(b);
        if (a == b) {
            changes.emplace_back(-1);
            return;
        }
        if (siz[b] < siz[a]) swap(a, b);
        parent[a] = b;
        changes.emplace_back(a);
        siz[b] += siz[a];
    }

    void rollback(int x) {
        /* rollback to x edges */
        while ((int)changes.size() > x) {
            auto g = changes.back();
            changes.pop_back();
            if (g == -1) continue;
            siz[parent[g]] -= siz[g];
            parent[g] = g;
        }
    }

    bool connected(int x, int y) {
        assert(x >= 0 and x < n and y >= 0 and y < n);
        return find(x) == find(y);
    }
};

void solve() {
    ll n, m;
    cin >> n >> m;

    vector<array<ll, 3>> edges(m);
    for (auto& [x, y, d] : edges) {
        cin >> x >> y >> d;
        x--; y--;
        d = -d;
    }

    ll q; cin >> q;
    const int B = 317;
    vector<array<ll, 3>> queries(q);
    for (auto& [T, b, r] : queries) {
        cin >> T >> b >> r;
        b--;
        r = -r;
    }

    vector<ll> ans(q, -1);

    vector<bool> visited_query(q, false);
    for (ll qid = 0; qid < q; qid += B) {
        vector<int> process;
        vector<bool> changed_edges(m, false);
        vector<int> change_list;
        vector change_times(m, vector<ll>());
        for (ll i = qid; i < min(qid + B, q); i++) {
            process.emplace_back(i);
            visited_query[i] = true;
        }

        for (auto query_idx : process) {
            auto& [type, r, b] = queries[query_idx];
            if (type == 1) {
                changed_edges[r] = true;
                change_times[r].pb(query_idx);
                change_list.pb(r);
            }
        }

        sort(all(change_list));
        change_list.erase(unique(all(change_list)), change_list.end());

        vector<int> unchanged_indices;
        for (int i = 0; i < m; i++) if (!changed_edges[i]) {
            unchanged_indices.pb(i);
        }

        sort(all(unchanged_indices), [&](int a, int b) {
            return edges[a][2] < edges[b][2];
        });

        debug(unchanged_indices);

        //must process all edges in --> increasing order
        sort(all(process), [&](int a, int b) {
            //if (queries[a][2] == queries[b][2]) return queries[a][0] < queries[b][0];
            return queries[a][2] < queries[b][2];
        });

        debug(process);

        auto get_weight = [&](int unchanged_index) -> ll {
            return edges[unchanged_indices[unchanged_index]][2];
        };

        int unchanged_ptr = 0;
        dsu_rollback dsu(n);
        for (int i = 0; i < process.size(); i++) {
            int u = process[i];
            auto& [T, r, b] = queries[u];
            
            while (unchanged_ptr < (int)unchanged_indices.size() and get_weight(unchanged_ptr) <= b) {
                auto& [e1, e2, w1] = edges[unchanged_indices[unchanged_ptr]];
                assert(w1 <= b);
                dsu.onion(e1, e2);
                unchanged_ptr++;
            }

            debug(u, unchanged_ptr);
            
            if (T == 1) {
            } else {
                for (auto& edge_num : change_list) {
                    auto& [p1, p2, original_weight] = edges[edge_num];
                    ll max_less = -1;
                    for (auto& query_idx : change_times[edge_num]) if (query_idx < u) {
                        max_less = max(max_less, query_idx);
                    }
                    if (max_less != -1) {
                        auto& [T, edge_point, new_weight] = queries[max_less];
                        assert(T == 1 and edge_point == edge_num);
                        if (new_weight <= b) dsu.onion(p1, p2);
                    } else {
                        if (original_weight <= b) dsu.onion(p1, p2);
                    }
                }
                int parent_node = dsu.find(r);
                ans[u] = dsu.siz[parent_node];
            }
            dsu.rollback(unchanged_ptr);
        }
        
        //update edges to be relevant
        for (auto query_idx : process) {
            auto& [type, b, r] = queries[query_idx];
            if (type == 1) {
                edges[b][2] = r;
            }
        }
    }

    for (int i = 0; i < q; i++) {
        int u = ans[i];
        assert(visited_query[i]);
        
        if (u != -1) {
            assert(queries[i][0] == 2);
            cout << u << '\n';
        }
    }
}

int main() {
    cin.tie(0)->sync_with_stdio(0);
    solve();
    return 0;   
}

Compilation message (stderr)

bridges.cpp: In function 'void solve()':
bridges.cpp:31:20: warning: statement has no effect [-Wunused-value]
   31 | #define debug(...) "zzz"
      |                    ^~~~~
bridges.cpp:136:9: note: in expansion of macro 'debug'
  136 |         debug(unchanged_indices);
      |         ^~~~~
bridges.cpp:31:20: warning: statement has no effect [-Wunused-value]
   31 | #define debug(...) "zzz"
      |                    ^~~~~
bridges.cpp:144:9: note: in expansion of macro 'debug'
  144 |         debug(process);
      |         ^~~~~
bridges.cpp:152:27: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  152 |         for (int i = 0; i < process.size(); i++) {
      |                         ~~^~~~~~~~~~~~~~~~
bridges.cpp:31:20: warning: statement has no effect [-Wunused-value]
   31 | #define debug(...) "zzz"
      |                    ^~~~~
bridges.cpp:163:13: note: in expansion of macro 'debug'
  163 |             debug(u, unchanged_ptr);
      |             ^~~~~
#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...