Submission #1337158

#TimeUsernameProblemLanguageResultExecution timeMemory
1337158baodatBridges (APIO19_bridges)C++20
0 / 100
3095 ms7328 KiB
#include <bits/stdc++.h>
using namespace std;
#define ll long long 
#define FOR(i, l, r) for(int i = l; i <= r; i++)
#define FORD(i, l, r) for(int i = l; i >= r; i--)
#define db double
#define ldb long double
#define all_1(x) (x).begin() + 1, (x).end()
#define all(x) (x).begin(), (x).end()
#define ins insert
#define pb push_back

template<typename T>void debug_var(const T& var, const string& name){
    cerr << name << ": " << var << "\n";
}
template<typename T>void debug_1d(const T& vt, const string& name){
    if(vt.empty()){
        cerr << name << " is empty!\n";
        return;
    }
    FOR(i, 0, (int)vt.size() - 1){
        cerr << name << "[" << i << "]: " << vt[i] << "\n";
    }
}

struct Edge{
    int u, v, id;
    ll w; 
};

struct Data{
    int type, which;
    ll w;
    int id;
};

struct DSU_rollback{
    int _n;
    vector<int> _par, _rnk, _sz;
    struct History{
        int u, v, rnk_u, sz_u;
    };
    stack<History> history;
    DSU_rollback(int n = 0){
        init(n);
    }
    void init(int n){
        while(!history.empty()) history.pop();
        _n = n;
        _par.assign(n + 1, 0);
        _rnk.assign(n + 1, 0);
        _sz.assign(n + 1, 1); 
        iota(all(_par), 0);
    }
    int find_u(int u){
        return _par[u] == u ? u : find_u(_par[u]);
    }
    void unite(int u, int v){  
        u = find_u(u);
        v = find_u(v);
        if(u == v) return;
        
        if(_rnk[u] < _rnk[v]) swap(u, v);
        history.push({u, v, _rnk[u], _sz[u]});
        
        if(_rnk[u] == _rnk[v]) ++_rnk[u];
        _sz[u] += _sz[v];
        _par[v] = u;
    }
    void rollback(int target_size){
        while((int)history.size() > target_size){
            History cur = history.top();
            history.pop();
            _par[cur.v] = cur.v;
            _sz[cur.u] = cur.sz_u;
            _rnk[cur.u] = cur.rnk_u;
        }
    }
};

int n, m, q;

void solve(){
    if (!(cin >> n >> m)) return;
    vector<Edge> edges(m + 1);
    FOR(i, 1, m){
        cin >> edges[i].u >> edges[i].v >> edges[i].w;
        edges[i].id = i;
    }
    
    cin >> q;
    vector<Data> queries(q + 1);
    FOR(i, 1, q){
        cin >> queries[i].type >> queries[i].which >> queries[i].w;
        queries[i].id = i;
    }

    vector<int> ans(q + 1, 0);
    int BLOCK = sqrt(m) * 2; 
    
    for(int L = 1; L <= q; L += BLOCK){
        int R = min(q, L + BLOCK - 1);
        
        vector<int> changed_edges, unchanged_edges, need_ans;
        vector<bool> is_changed(m + 1, false); 
        
        FOR(i, L, R){
            if(queries[i].type == 2) need_ans.pb(i);
            else is_changed[queries[i].which] = true;
        }
        
        FOR(i, 1, m){
            if(is_changed[i]) changed_edges.pb(i);
            else unchanged_edges.pb(i);
        }
        
        sort(all(need_ans), [&](int a, int b){
            return queries[a].w > queries[b].w;
        });
        
        sort(all(unchanged_edges), [&](int a, int b){
            return edges[a].w > edges[b].w;
        });
        
        DSU_rollback dsu(n);
        int edge_ptr = 0;
        
        for(int q_idx : need_ans){
            while(edge_ptr < (int)unchanged_edges.size() && edges[unchanged_edges[edge_ptr]].w >= queries[q_idx].w){
                dsu.unite(edges[unchanged_edges[edge_ptr]].u, edges[unchanged_edges[edge_ptr]].v);
                edge_ptr++;
            }
            
            int checkpoint = dsu.history.size();
            for(int e_idx : changed_edges){
                ll weight_now = edges[e_idx].w;
                FOR(k, L, q_idx){
                    if(queries[k].type == 1 && queries[k].which == e_idx){
                        weight_now = queries[k].w;
                    }
                }
                if(weight_now >= queries[q_idx].w){
                    dsu.unite(edges[e_idx].u, edges[e_idx].v);
                }
            }
            
            ans[q_idx] = dsu._sz[dsu.find_u(queries[q_idx].which)];
            dsu.rollback(checkpoint);
        }
        
        FOR(i, L, R){
            if(queries[i].type == 1){
                edges[queries[i].which].w = queries[i].w;
            }
        }
    }
    
    FOR(i, 1, q) if(queries[i].type == 2) cout << ans[i] << "\n";
}

/*
given a undirected graph with n vertices m edges initally each edges have a weight d_i
q queries
update -> set edges i to x_i
query -> how many vertices we can reach if we start from s_i and this car have weight x_i?
(x_i >= d_i)

cool first thing we noticed... krt and hld aint working
okay let's try sqrt decomp
each block contain 1k queries
okay what do we do nxt?
let's define 2 type of edges
unchanged -> didn't change anything in the entire block
changed -> change atleast 1 time
there are atmost q changed edges
and the rest are unchanged
we can keep changed and use it for the next update
if we sort the car weight decreasing

*/

signed main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    int t = 1;
    //cin >> t;
    while(t--){
        solve();
    }
    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...