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: