競技プログラミング日記

主に AtCoder の記事です

PAST12K問題

PAST12K

解法
Easy

削除のみの場合. クエリを先読みして,逆に処理すれば,union-find で解ける.

Normal

追加と削除の場合. ただし,追加する辺が 10個以下.
この場合もベースになるのは Easy版で,クエリ先読みと逆順処理をする. もとのクエリで追加する辺(逆順処理では削除する辺)は少ないので, その度に union-find を構成しなおしても間に合う.

実装

Union-find を再構成するために, 逆順で処理したときに,追加した辺を記録しておく.

使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"

int main() {
  ll n,m;
  cin >> n >> m;
  UnionFind<ll> uf;
  set<pll> es;
  rep(i,m){
    ll a,b; cin >> a >> b;
    --a, --b;
    es.insert({a,b});
  }

  ll q; cin >> q;
  vector<tuple<ll,ll,ll>> qs;
  rep(qi,q){
    ll t,x,y; cin >> t >> x >> y;
    --x,--y;
    qs.emplace_back(t,x,y);

    if(t == 1){
      es.insert({x,y});
    }else if(t == 2){
      assert(es.find({x,y}) != es.end());
      es.erase({x,y});
    }
  }
  reverse(all(qs));

  auto create_uf = [&](void) -> UnionFind<ll> {
    UnionFind<ll> ret(n);
    for(auto [a,b]: es){
      ret.merge(a,b);
    }
    return ret;
  };
 
  uf = create_uf();

  vector<string> ans;
  for(auto [t,x,y]: qs){
    if(t == 1){
      es.erase({x,y});
      uf = create_uf();
    }else if(t == 2){
      es.insert({x,y});
      uf.merge(x,y);
    }else{
      ans.push_back(uf.same(x,y) ? "Yes" : "No");
    }
  }
  reverse(all(ans)); // rem: reverse

  for(auto s: ans){
    cout << s << endl;
  }


  return 0;
}