Official

E - Graph Destruction Editorial by sugarrr


この問題では連結成分を扱うので Union-Find を使いたいですが、Union-Find では辺の追加はできるものの辺の削除はできません。

ここで、クエリ系の問題の常套手段である「逆から処理する」というテクニックを思い出すと、おおむね問題が以下のように言い換えられます。

頂点 \(N,N-1,\ldots,1\) を順番にグラフに追加していく。
頂点 \(i\) を追加すると同時に、\(i\)\(j(j\gt i)\) を結ぶ辺もグラフに追加する。
頂点 \(i\) まで追加したときのグラフの連結成分の個数は?

これは Union-Find を用いて容易に求めることができます。
なお、Union-Find は ACL の dsu というライブラリを用いると便利です。 下の実装例も参考にしてください。

#include<bits/stdc++.h>
using namespace std;
#include<atcoder/all>
using namespace atcoder;
typedef long long ll;

signed main(){
    ll n,m;cin>>n>>m;
    vector<vector<ll>>v(n+1);
    while(m--){
        ll a,b;cin>>a>>b;
        v[a].push_back(b);
    }
    dsu d(n+1);
    vector<ll>res={0}; //頂点 N まで消した時の答えは必ず 0
    ll ans = 0; // 今の連結成分の数
    for(ll i=n;i>=2;i--){
        ans++; //頂点 i を追加
        for(auto j:v[i]){
            if(!d.same(i,j)){
                d.merge(i,j);
                ans--; //非連結の頂点同士を繋げたとき、連結成分の数は 1 減る
            }
        }
        res.push_back(ans);
    }
    reverse(res.begin(),res.end());
    for(auto x:res)cout<<x<<endl;
    return 0;
}

posted:
last update: