Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DSU on Tree

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for camypaper camypaper
November 07, 2017
4.3k

DSU on Tree

Avatar for camypaper

camypaper

November 07, 2017
Tweet

Transcript

  1. Q:ツリー上のマージテク亜種? A: CF383 Div.1 D の想定解で紹介されたやつ - (本家ではGuni(英語だとsackの意味)で呼ばれる) - (日本語では)名前はまだない?

    詳しくは以下を見た方がよい http://codeforces.com/blog/entry/44351 僕の理解をもとにかいつまんで紹介 - 正確には彼らが紹介したい方法とはちょっと違います(上のURLでの3番)
  2. 問題 • N 頂点の K 種類の色で頂点彩色された 根付き木が与えられる • 頂点 i

    は色 Ci で塗られている • 以下の Q 個のクエリを処理せよ – 頂点 ai を根とする部分木に含まれる 色 bi で塗られた頂点の数を求めよ • N, Q, K ≦ 105 ぐらい
  3. 解法 • mapに(色, 個数)を持ってdfsしながら マージをがんばる – mapどうしはマージテクでマージ • O(N log2N)

    でできる – unordered_map を使うとlogが一個落ちる – でも重い • 今回は O(N logN) で軽めの定数倍で やります、という話
  4. 用意する関数 • dfs1(v) – v を根とする根付き木について処理 – 結果として 「v を根とする部分木に含まれる

    各色の頂点がいくつあるか」を返す • dfs2(v) – v を根とする根付き木について処理 – 結果は返さない
  5. dfs1(v) • v の直接の子孫を u1 , u2 , u3 ,

    … , uk とする – 部分木のサイズの降順で並んでいる,とする • u2 , u3 , u4 , … , uk についてdfs2で処理 • u1 についてdfs1で処理して結果を受け取る – これを A とする • u2 , u3 , u4 , … , uk を根とする部分木に 含まれる頂点の色を全て調べて A に加算 • v 自身の色を A に加算 – このタイミングでクエリについて処理 • A を返す
  6. dfs2(v) • v の直接の子孫を u1 , u2 , u3 ,

    … , uk とする – 部分木のサイズの降順で並んでいる,とする • u2 , u3 , u4 , … , uk についてdfs2で処理 • u1 についてdfs1で処理して結果を受け取る – これを A とする • u2 , u3 , u4 , … , uk を根とする部分木に 含まれる頂点の色を全て調べて A に加算 • v 自身の色を A に加算 – このタイミングでクエリについて処理 • vを根とする部分木に含まれる頂点の色を 全て調べて A から減算
  7. Q: 疑問 Q1: A を作る度に O(K) じゃん Q2: dfs2 で

    A から減算するパートが 明らかに不要に見えるんだけど??? A: A は 1 回だけ作って使いまわして解決 (そのためにdfs2で A から減算する) (さっきは分かりやすさのために説明を省きました)
  8. アルゴリズム(簡易まとめ) • はじめに A を 1 個作る(使いまわす) • 根からdfsをする(dfs1でもdfs2でもよい) –

    子孫たちのうち,サイズが最大のもの以外をdfs2で処理 • A は全て 0 のまま – サイズが最大のものをdfs1で処理 • A にデータが入る – 子孫たちのうち,最大のもの以外を全て追加 – 自身を追加 • ここで A は部分木全体について処理された状態になる – クエリに答える – (dfs2なら)子孫たちのうち,最大のもの以外を全て削除 • 削除されると A は全て 0 になる
  9. • はじめに A を 1 個作る(使いまわす) • 根からdfsをする(dfs1でもdfs2でもよい) – 子孫たちのうち,サイズが最大のもの以外をdfs2で処理

    • A は全て 0 のまま – サイズが最大のものをdfs1で処理 • A にデータが入る – 子孫たちのうち,最大のもの以外を全て追加 – 自身を追加 • ここで A は部分木全体について処理された状態になる – クエリに答える – (dfs2なら)子孫たちのうち,最大のもの以外を全て削除 • 削除されると A は全て 0 になる アルゴリズム(簡易まとめ) この2つはさらに 別のdfs等で処理
  10. 計算量解析 • 各頂点についてdfs1 か dfs2 が 1 回行われる • dfs1,

    dfs2 で破線の先の部分木をなめる操作, dfs2 での最後に部分木を全てなめる操作の 2 つがボトルネック • ある頂点について,なめられる回数は O(logN) – 根にたどり着くまでに辿る破線の数の 2 倍回ぐらい なめられる – 破線はHL分解でのlight edgeなので O(logN) 回で済む • N 個の頂点があるから O(NlogN)
  11. まとめ • 各頂点を根とする部分木において 各色が含まれる数を求める,というのが 時間 O(NlogN), 空間 O(N + K)

    でできた • 利点と欠点 – unordered_mapを使うのに比べて定数倍が軽い – 実装はただマージテクするより少し重い