AtCoder Regular Contest 056 B - 駐車場
解法
答えに x が含まれるかどうかは, 以下のようにして判定できます。
- x 以上の頂点のみを用いて, S から x に到達できる。
これはなぜかというと, もし x 未満の頂点 y が行き止まりになっておらず, その頂点を使って x に到達できたとすると, y は明らかに昔も通れたはずなので, y が行き止まりになっていないのはおかしいです。
逆に, x 以上の頂点のみを用いて S から x に到達できたとすると, 答えが x に到達できるのは自明です。
ということで, 上記の条件を高速に判定できれば良いのですが, これは頂点の大きい順に判定していくと unionfind を使って簡単にできます。
頂点 x について判定したい場合, 辺(u, v) が x <= u, x <= v を満たす場合に (u, v) を連結させるようにすると良いです。
struct UnionFind { vector<int> par; int n, cnt; UnionFind(const int& x = 0) {init(x);} void init(const int& x) {par.assign(cnt=n=x, -1);} inline int find(const int& x) {return par[x] < 0 ? x : par[x] = find(par[x]);} inline bool same(const int& x, const int& y) {return find(x) == find(y);} inline bool unite(int x, int y) { if ((x = find(x)) == (y = find(y))) return false; --cnt; if (par[x] > par[y]) swap(x, y); par[x] += par[y]; par[y] = x; return true; } inline int count() const {return cnt;} inline int count(int x) {return -par[find(x)];} }; int main() { cin.tie(0); ios::sync_with_stdio(false); int N, M, S; cin >> N >> M >> S; --S; vector<pii> es(M); vector<int> ans; for (int i = 0; i < M; i++) { int u, v; cin >> u >> v; --u; --v; if (u > v) swap(u, v); es[i] = pii(u, v); } sort(es.rbegin(), es.rend()); int cur = 0; UnionFind uf(N); for (int i = N-1; i >= 0; i--) { while (cur < M && es[cur].first >= i) { uf.unite(es[cur].first, es[cur].second); cur++; } if (uf.same(i, S)) ans.push_back(i); } reverse(ans.begin(), ans.end()); for (int el : ans) cout << el+1 << endl; return 0; }