競技プログラミング日記

主に AtCoder の記事です

AtCoder Regular Contest 106B

ARC106B

連結成分毎に考えてよい. 連結なグラフで考えるとき,まずはtreeで考えるとよい. Spannig treeを用いて,treeの場合に帰着できるケースも多いし, まずtreeで解けないと,一般の場合は話にならない.

また,操作の性質として,操作によって値の総和が不変であることが分かる.

Treeで考えると,葉から値を決めていけばよい. もしtreeのvertex が2個以上なら,最後に2箇所だけ値が定まってない状態になる. このときに,+x, -x の形になっているのが,条件を満たす必要十分条件. つまり,vertex に書いてある値の和が0であることが必要十分. これは,vertex の個数が1個の場合でも成立.

この考えをspanning tree に適用すれば, treeでない連結成分でも同様.

実装するときは,vertex  i  b_{i}-a_{i} を書き込めばよい. DFS, Uinon-find どちらで連結成分を判定してもAC.

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

int main() {
  ll n, m;
  cin >> n >> m;
  vll v(n);
  vll va(n), vb(n);
  cinv(va);
  cinv(vb);

  rep(i,n){
    v[i] = vb[i] - va[i];
  }
 
  UnionFind<ll> uf(n);
  vvll to(n);
  rep(i,m){
    ll c,d ; cin >> c >> d;
    --c,--d;
    uf.merge(c,d);
    to[c].push_back(d);
    to[d].push_back(c);

  }

  {// AC : union-find
    vll x(n);
    rep(i,n){
      x[uf[i]] += v[i];
    }
    bool any = true;
    rep(i,n){
      if(x[i]!=0) any = false;
    }
    yesno(any);

  }


  { // AC : dfs
    // vll vis(n);
    // ll s = 0;
    // auto dfs = [&](auto f, ll cu, ll pa) -> void {
    //  if(vis[cu]) return ;
    //  vis[cu] = true;
    //  s += v[cu];

    //  fore(ne, to[cu]) if(ne != pa){
    //    f(f, ne, cu);
    //  }
    // };

    // rep(i,n) if(!vis[i]){
    //  s = 0;
    //  dfs(dfs, i, -1);
    //  if(s != 0) {
    //    cout << "No" << endl;
    //    return 0;
    //  }
    // }
    // cout << "Yes" << endl;

   
  }



#endif

  return 0;
}