#ifdef ONLINE_JUDGE
#endif // ONLINE_JUDGE
#include <bits/stdc++.h>
using namespace std;
#define F first
#define S second
#define FOR(i, a, b) for(int i = (a), _b = (b); i <= _b; ++i)
#define FORD(i, a, b) for(int i = (a), _b = (b); i >= _b; --i)
#define REP(i, n) for(int i = 0, _n = (n); i < _n; ++i)
#define mp make_pair
#define all(v) v.begin(), v.end()
#define uni(v) v.erase(unique(all(v)), v.end())
const int maxN = 100000 + 5;
int n, m, q;
pair<int,int> edge[maxN];
int w[maxN];
int type[maxN], cen[maxN], reqW[maxN];
int ans[maxN];
// simple rollback DSU (no path compression), union by size
struct RollbackDSU {
int n;
vector<int> parent, sz;
vector<pair<int,int>> ops; // (v, old_sz_of_root) store v's parent before union and size of new root before merge
RollbackDSU(int n = 0){ init(n); }
void init(int _n){
n = _n;
parent.assign(n+1, 0);
sz.assign(n+1, 0);
for(int i=1;i<=n;i++){ parent[i]=i; sz[i]=1; }
ops.clear();
}
int find(int v){
while(parent[v] != v) v = parent[v];
return v;
}
bool unite(int a, int b){
a = find(a); b = find(b);
if(a == b) return false;
if(sz[a] < sz[b]) swap(a,b);
// record b's parent and size of a before merge
ops.emplace_back(b, sz[a]);
parent[b] = a;
sz[a] += sz[b];
return true;
}
void rollbackOne(){
if(ops.empty()) return;
auto pr = ops.back(); ops.pop_back();
int b = pr.first;
int old_sz_a = pr.second;
int a = parent[b]; // current parent
// revert
sz[a] = old_sz_a;
parent[b] = b;
}
void rollbackToSize(size_t s){
while(ops.size() > s) rollbackOne();
}
int compSize(int v){
int r = find(v);
return sz[r];
}
};
struct Snapshot {
int idx; // original query index
int s; // start node
int w; // threshold
vector<int> changed_applicable; // ids of changed edges that meet threshold at query time
};
void process(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
if(!(cin >> n >> m)) return;
FOR(i,1,m){
int u,v,d; cin >> u >> v >> d;
edge[i] = {u,v};
w[i] = d;
}
cin >> q;
FOR(i,1,q){
cin >> type[i] >> cen[i] >> reqW[i];
}
RollbackDSU dsu(n);
int BLOCK = max(1, (int)sqrt(q) ); // good default
for(int L = 1; L <= q; L += BLOCK){
int R = min(q, L + BLOCK - 1);
// 1) find changed edge ids in this block
vector<char> isChanged(m+1, 0);
for(int i = L; i <= R; ++i){
if(type[i] == 1){
isChanged[cen[i]] = 1;
}
}
vector<int> changedIds;
changedIds.reserve(BLOCK);
for(int eid = 1; eid <= m; ++eid) if(isChanged[eid]) changedIds.push_back(eid);
// 2) unchanged edges list (weight, id) using current global w[]
vector<pair<int,int>> unchanged;
unchanged.reserve(m);
for(int eid = 1; eid <= m; ++eid){
if(!isChanged[eid]) unchanged.emplace_back(w[eid], eid);
}
sort(unchanged.begin(), unchanged.end(), [](const pair<int,int>& a, const pair<int,int>& b){
return a.first > b.first; // descending by weight
});
// 3) simulate block to build snapshots for queries: need tmpW that applies updates inside block sequentially
vector<int> tmpW(m+1);
FOR(eid,1,m) tmpW[eid] = w[eid];
vector<Snapshot> snaps;
snaps.reserve(R-L+1);
for(int i = L; i <= R; ++i){
if(type[i] == 1){
// apply update to tmpW for subsequent queries in this block
int bid = cen[i], neww = reqW[i];
tmpW[bid] = neww;
} else {
Snapshot s;
s.idx = i;
s.s = cen[i];
s.w = reqW[i];
// collect changed edges with tmpW >= s.w
for(int id: changedIds){
if(tmpW[id] >= s.w) s.changed_applicable.push_back(id);
}
snaps.push_back(move(s));
}
}
// 4) sort snapshots by w desc and process: add unchanged edges progressively, union changed_applicable per snapshot (with rollback)
int szSnaps = (int)snaps.size();
vector<int> order(szSnaps);
iota(order.begin(), order.end(), 0);
sort(order.begin(), order.end(), [&](int a, int b){
return snaps[a].w > snaps[b].w;
});
// init DSU
dsu.init(n);
size_t ptr = 0; // pointer in unchanged
for(int ordIdx = 0; ordIdx < szSnaps; ++ordIdx){
Snapshot &S = snaps[order[ordIdx]];
// bring unchanged edges with weight >= S.w
while(ptr < unchanged.size() && unchanged[ptr].first >= S.w){
int eid = unchanged[ptr].second;
dsu.unite(edge[eid].first, edge[eid].second);
++ptr;
}
size_t saveSize = dsu.ops.size();
// add changed_applicable temporarily
for(int eid : S.changed_applicable){
dsu.unite(edge[eid].first, edge[eid].second);
}
ans[S.idx] = dsu.compSize(S.s);
dsu.rollbackToSize(saveSize);
}
// 5) apply all updates in block to global w[]
for(int i = L; i <= R; ++i){
if(type[i] == 1){
int bid = cen[i], neww = reqW[i];
w[bid] = neww;
}
}
}
FOR(i,1,q){
if(type[i] == 2) cout << ans[i] << '\n';
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
process();
return 0;
}
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |