競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 304E

ABC304E

クエリ問題で,一つのクエリにつき高速に求める. 良いグラフの定義通りだと,全ての\(i \in K\)に対して調べることになるが, クエリでは1本しか辺を追加しないので,変化は少ない. クエリ毎に共通して使える部分が多くあるので,そこを前処理しておく.

良いグラフか判定する際,連結成分毎に考えれば良い. 各連結成分ごとに\(x_{i}, y_{i}\)が含まれているかが重要で, それ以外はグラフの形は影響しない.
クエリで調べたいことは,異なる連結成分2つが与えられたとき, それを結んで良いかどうか.これを前処理する.

あとは\(O(N), O(Nlog N)\)(または\(N\)を\(M,K\)に変えたもの)など,高速で前処理を済ませたい. 連結成分の個数は,最大で\(O(N)\)になる. 結んではいけない連結成分の組をもとめておけば, \(O(Klog K)\)で前処理できる. クエリごとにも\(O(log K)\)でできるので, 合計で \(O*1;

  }


  return 0;
}

*1:K+Q)log K)\).

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

int main() {
  ll n,m; cin >> n >> m;
  vvll to(n);
  UnionFind<ll> uf(n);
  rep(i,m){
    ll a, b; cin >> a >> b;
    --a, --b;
    to[a].push_back(b);
    to[b].push_back(a);

    uf.merge(a,b);
   
  }

  ll k; cin >> k;
  vll x(k), y(k);
  rep(i,k){
    cin >> x[i] >> y[i];
    x[i]--; y[i]--;
   
  }

  set<pll> st; // ng
  rep(i,k){
    ll ax = uf[x[i]];
    ll ay = uf[y[i]];
    assert(ax != ay);
    if(ax > ay) swap(ax, ay);
    st.insert({ax, ay});
  }

  ll q; cin >> q;
  rep(qi,q){
    ll a,b; cin >> a >> b;
    --a, --b;

    a = uf[a];
    b = uf[b];
    if(a > b) swap(a,b);

    pll pa = {a,b};
    yesno(!in(pa, st