目次
AtCoder Beginner Contest 453 E,F,G問題メモ
E - Team Division
問題文
- 選手 $1$、選手 $2$、$\ldots$、選手 $N$ の $N$ 人を、次の条件をすべてみたすように $2$ つの(区別できる)チーム $A,B$ に分けます。
- それぞれのチームは $1$ 人以上の選手からなる。
- それぞれの選手はチーム $A,B$ のちょうど一方に属する。
- 選手 $i$ が所属するチームに属する人数は $L_i$ 人以上 $R_i$ 人以下である。
- 条件をみたすような分け方は何通りあるか求め、その値を $998244353$ で割ったあまりを出力してください。
- ただし、$2$ つの分け方が異なるとは、ある選手が存在してその選手の属するチームが異なることをさします。
制約
- $2\leq N\leq 2\times 10^5$
- $1\leq L_i\leq R_i\leq N-1$
- 入力はすべて整数
解法
まず、いろいろなアプローチがありそうで方針に迷い、また正しい解法に思い至っても条件を網羅するのがまた難しい。
チーム $A,B$ に入れる人数をそれぞれ $a,b$ と固定する($b=N-a$)。その時のチームの分け方を $f(a)$ とする。
分け方は対称的なので、$a \le b$ の範囲で $a$ を動かして分け方の数を求め、
- $a \lt b$ の時、$2f(a)$
- $a = b$ の時、$f(a)$
の総和が全体の答えとなる。
$f(a)$ の求め方だが、各選手の $L_i,R_i$ が $a,b$ をそれぞれ含むか調べ、グルーピングする。
- $a$ も $b$ も含む → グループ $P$
- $a$ は含むが $b$ は含まない → グループ $Q$
- $a$ は含まないが $b$ は含む → グループ $R$
- $a$ も $b$ も含まない → グループ $S$
また、各グループの要素数を $p,q,r,s$ で表すことにする。
まず、無理な条件を挙げる。
- $s \ge 1$ なら無理($S$ の選手はどちらにも入れられない)
- $q \gt a$ なら無理($Q$ の選手は A にしか入れられないが、この時点で A を $a$ 人にできない)
- $r \gt b$ なら無理($R$ の選手は B にしか入れられないが、この時点で B を $b$ 人にできない)
そうでない場合、$Q,R$ の選手をそれぞれ $A,B$ に入れた後、$P$ の選手を $Q$ と $R$ に人数が合うように振り分ける。
つまり、$p$ を $(a-q)$ と $(b-r)$ に分割する方法の数 ${}_p C_{a-q}$ が分け方の数となる。
だが、$p,q,r,s$ を $a=1,2,3,...$ のたびに調べていては $O(N^2)$ なのでダメ。1つ前からの差分を考えたい。
ある選手 $i$ が、$(a,b)=(1,N-1),(2,N-2),...,(\lfloor \frac{N}{2} \rfloor,\lceil \frac{N}{2} \rceil)$ と動かす過程で、どのようにグループを遷移するか考える。
- 始めは $S$
- $a=\min(L_i,N-R_i)$ に固定するタイミングで、$Q,R$ のいずれかに入る。
- または同じならいきなり $P$ に入る
- 以下の早い方で、$P$ か $S$ に入る。
- $a=\max(L_i,N-R_i)$ に固定するタイミングで、$P$ に入る。
- $a=\min(R_i,N-L_i)$ の固定が終了したタイミングで、$S$ に入る。
- その後、その選手は(今回の $a$ の探索範囲では)ずっと $P$ か $S$ に入り続ける。
よって、各選手がグループ $P,Q,R$ にそれぞれ存在するような $a$ の値は区間をなすので、 各 $a$ の時の $p,q,r,s$ の値は累積和で前計算可能である。
N=20 L R a=1 2 3 4 5 6 7 8 9 10 5 12 S S S S Q Q Q P P P 7 15 S S S S R R P P P P 4 7 S S S Q Q Q Q S S S
あとは、前述の無理な条件に当てはまらないかをチェック後、${}_p C_{a-q}$ を求めていけばよい。
F - Avoid Division
問題文
- $N$ 頂点の木が与えられます。
- 高橋君は各頂点を色 $1$、色 $2$、$\ldots$、色 $K$ のうちいずれか一色で塗ります。
- 色 $i$ は最大で $C_i$ 個の頂点を塗るのに使うことができます。
- 次の条件をみたすように頂点を塗ることが可能か判定し、可能な場合は条件をみたす塗り方を $1$ つ出力してください。
- どの辺についても、ある $i$ $(1\leq i\leq K)$ が存在して、その辺で木を切って得られる $2$ つの部分木の両方に色 $i$ で塗られた頂点が存在する。
- $T$ 個のテストケースが与えられるので、それぞれについて答えを求めてください。
制約
- $1\leq T\leq 10^5$
- $2\leq N\leq 3\times 10^5$
- $1\leq K\leq N$
- $1\leq U_i,V_i\leq N$
- 与えられるグラフは木である。
- $1\leq C_i\leq N$
- $C_1+C_2+\cdots+C_K\geq N$
- 入力はすべて整数
- 各入力のテストケースにわたる $N$ の総和は $3\times 10^5$ を超えない。
解法
解法に辿り着くまでの道は地続きなように見える(素直に考察を進めていけば辿り着けそう)けど、 なんか本番では思いつけなかったし、他の人もそうだったのか異様にAC数が少なかった。 G問題が典型問題に近く、そちらに先に手を付けた人が多いのも理由か。
条件を満たす色の塗り方は、言い換えると以下のようになる。
- 「同じ色で塗られた2頂点を選び、その頂点間のパス上の辺を黒く塗る」という操作を好きなだけおこなえる
- この時、全ての辺を黒く塗ることが可能である
$C_i=1$ の色は辺を黒く塗る助けにならないので、 重要なのは $W=\displaystyle \sum_{C_i \ge 2}C_i$、つまり「2個以上の頂点を塗れる色」で塗れる頂点の個数である。
特に、葉が重要である。葉は必ず2個以上の頂点を塗れる色で塗らないといけない。
葉の個数を $L$ として、$L \gt W$ なら不可能。
以下、$L \le W$ とする。
この場合に必ず可能かどうかはまだわからないが、
上手く全ての辺を黒く塗れるような葉同士のペアの作り方がないか考える。
それさえできれば、葉でない頂点はどのように色を塗っても良いことになる。
ここで、やや唐突だが「木の重心」を思い起こす。 木の重心とは、「その頂点を根とすると、根の子それぞれの部分木のサイズが全て、元の木の半分以下になるような頂点」のことである。
異なる部分木に含まれる2つの葉を同じ色で塗れば、それぞれの葉~重心間のパスが塗られることになる。
◎重心
⇗⇖
○ ○
⇗\ ⇗\
① ○ ① ○
もし、全ての葉について「異なる部分木に含まれる葉のいずれかに、自身と同じ色がある」 という塗り方ができれば、条件を達成できるが、、、
ただし、重心の場合、1つの部分木に過半数の葉が集中してしまい、そのような塗り方ができない可能性がある。
◎重心
/ \
○ ○
//||\\ \
oooooooo ○-○-○...-○
葉が沢山 葉が1個
単なる重心ではダメだが、少し応用して
- その頂点を根とすると、根の子それぞれに含まれる葉の個数が全て、木全体の葉の個数の半分以下になるような頂点
- “葉の重心”とでも呼ぶことにする。必ず存在することが示せる(証明略)
を見つければ、必ず条件を達成できる。
葉の重心からDFSして、葉のみを訪問順に並べる。
それを更に 1個目、$\lceil L/2 \rceil$ 個目、2個目、$\lceil L/2 \rceil +1$ 個目、、、の順に並び替えれば、
隣り合う2つの葉は必ず異なる部分木に存在することが保証される。
この順に、$C_i \ge 2$ である色につき、$C_i$ 個の葉を $i$ で塗る、ということを繰り返せばよい。
もし、最後の葉 $v$ に塗った色 $c$ が、その時点で $v$ 1頂点にしか塗られていない場合、 葉の重心も色 $c$ に塗るとよい。
G - Copy Query
問題文
- $N$ 個の長さ $M$ の数列 $A_1,A_2,\dots,A_N$ があります。最初は全ての数列の全ての要素が $0$ です。
- 以降、数列 $A_i$ の $j$ 項目を $A_{i,j}$ と表します。
- 以下の $3$ 種類のクエリを、与えられた順に合計 $Q$ 個処理してください。
- タイプ $1$ : 数列 $A_{X_i}$ を数列 $A_{Y_i}$ で上書きする。つまり、全ての整数 $j$ ($1 \le j \le M$) について、 $A_{X_i,j}$ を $A_{Y_i,j}$ に変更する。
- タイプ $2$ : 数列 $A_{X_i}$ の $Y_i$ 項目、すなわち $A_{X_i,Y_i}$ を $Z_i$ に変更する。
- タイプ $3$ : 数列 $A_{X_i}$ について、 $L_i$ 項目から $R_i$ 項目までの和、すなわち $A_{X_i,L_i}+A_{X_i,L_i+1}+\dots+A_{X_i,R_i}$ を出力する。
制約
- $1 \le N,M \le 2 \times 10^5$
- $1 \le Q \le 2 \times 10^5$
- タイプ $1$ のクエリは以下の制約を満たす
- $1 \le X_i,Y_i \le N$
- タイプ $2$ のクエリは以下の制約を満たす
- $1 \le X_i \le N$
- $1 \le Y_i \le M$
- $0 \le Z_i \le 10^9$
- タイプ $3$ のクエリは以下の制約を満たす
- $1 \le X_i \le N$
- $1 \le L_i \le R_i \le M$
- 入力はすべて整数
解法
クエリ先読み + オイラーツアー。
$i=1,2,...,N$ に対し、数列 $A_i$ を、実体では無く「参照番号」で保持することにする。
クエリ番号を便宜的に参照番号として用い、
「クエリ $q$ で対象となった数列の、クエリ反映直後の状態」を「ref $q$」とする。
各 $A_i$ が、今、どの ref を参照しているかを、$R_i$ で表す。
こうすれば、タイプ1は参照を貼り替えるだけで済む。$R_{X_q}←R_{Y_q}$
初期状態(全てが $0$ の数列)は ref $0$ とし、最初、全ての $i$ に対し $R_i=0$ とする。
タイプ2では、実際に数列に変更が生じる。
クエリ対象の数列 $X_q$ の、その時点の ref は $R_{X_q}$ であり、処理後は $q$ に変更される。
「ref $q$ は、ref $R_{X_q}$ が表す数列の $Y_q$ 番目を $Z_q$ に変更したものである」という関係性を有向辺で表すと、 タイプ2によって生成される全ての ref は、ref $0$ を根とした木構造を形成する。
⓪ [0, 0, 0]
(Y=1,Z=2) ↓
① [2, 0, 0]
(Y=2,Z=7) ↓
② [2, 7, 0]
(Y=3,Z=3) ↙↘ (Y=1,Z=5)
[2, 7, 3] ③ ⑤ [5, 7, 0]
よって、全要素 $0$ で初期化したセグメント木 $S$ を保持し、 この木をオイラーツアーで辿りながら辺が表すタイプ2のクエリを $S$ に反映させたり、 親に戻るときはその反映を戻したりして管理し、 その過程で タイプ3 で必要になった ref に対して答えを求めていけば、$O(N+Q \log{M})$ で全てのクエリに答えられる。
オンラインクエリ対応
いつの間にか AtCoder Algorithm Lectures なんてページができてて、高度なデータ構造も含め様々な概念・テクニックが解説されている。
その中の1つ、永続セグメント木を使えば、オンラインでクエリに答えなければならない状況でも対応できる。
各数列を参照 $R_i$ で管理するところは同じ(永続セグメント木は、「根のノードインスタンス」がそのセグメント木全体への参照として使える)
クエリによる更新が入ると、更新前の状態は残したまま、セグ木の各ノードのうち更新が発生した $O(\log{M})$ 個のノードだけが複製される、というイメージ。
階層とindexの綺麗な対応は作れないので、配列ではなくノードインスタンスを作っていく実装になる。遅い言語ではTLEに若干注意。

