June 23, 2020
クエリが与えられ、それぞれのクエリに対して、Union-Findで条件を満たす連結成分の個数を数える問題。 クエリの先読みをするんだけど、別に与えられた順番で考える必要はなくて、都合のいい(今回で言うと、一番新しい年度をもつ)クエリから考えればいいという問題。
template<typename T> struct UnionFind { i64 sz; vector<T> parent; vector<i64> rank; UnionFind(i64 n) : sz(n) { parent.assign(n, 0); REP(i, n) { parent[i] = i; } rank.assign(n, 1); } T find(T t) { if (parent[t] == t) return t; return parent[t] = find(parent[t]); } bool unite(T t1, T t2) { t1 = find(t1); t2 = find(t2); if (t1 == t2) return false; if (rank[t1] < rank[t2]) swap(t1, t2); parent[t2] = t1; rank[t1] += rank[t2]; return true; } bool same(T t1, T t2) { return find(t1) == find(t2); } }; #define MAX_N 100'000 using P = pair<i64, i64>; using E = pair<i64, P>; int main() { i64 N, M; cin >> N >> M; vector<E> edge(M); REP(i, M) { i64 u, v, y; cin >> u >> v >> y; u--, v--; edge[i] = {y, {u, v}}; } sort(edge.rbegin(), edge.rend()); i64 Q; cin >> Q; vector<tuple<i64, i64, i64>> query(Q); REP(i, Q) { i64 u, w; cin >> u >> w; u--; query[i] = make_tuple(w, u, i); } sort(query.rbegin(), query.rend()); UnionFind<i64> uf(N); i64 ei = 0; vector<i64> ans(Q); REP(q, Q) { auto [w, u, i] = query[q]; while (ei < M && edge[ei].first > w) { P p = edge[ei].second; uf.unite(p.first, p.second); ei++; } ans[i] = uf.rank[uf.find(u)]; } REP(i, Q) cout << ans[i] << endl; return 0; }