2020北大集訓題解

能聽懂的就盡力寫吧。代碼肯定是都咕了。

Day 1

T1

再次感謝出題人不殺之恩,給了我 89 分這個鬼畜分數。

做法(不是寫法)和正解完全一樣,然而還是不知道自己怎麼錯了。

心情好了再去看 https://uoj.ac/problem/427 。這題不僅被甩了 11 分還花了 3h ……

T2

真就聯賽模擬題啊 /jk

獲得成就:上臺講題。

先考慮一個區間怎麼做。對於每個位置直接處理出 \(pre_i\) 表示往前第一個不被包含在它的子樹內的位置,可以線段樹二分求出。然後就是一個二維數點。

多個區間的話,相當於給這個區間加了一個額外限制,即必須是某個點 \(L\) 的祖先。同樣先線段樹二分,得到第一個滿足該條件的點(然而寫這句話的時候發現這好像不太好做,所以要線段樹二分出這個區間的一個前綴,使得前綴的 \(lca\) (好像 \(lca\) 也不好搞,只能是關於 dfs 序的某些東西)是 \(L\) 的祖先。所以我場上寫的線段樹二分可能複雜度還是錯的???)。此時,前綴的所有點都一定不滿足條件,而對於後面的點,如果子樹中能包含這個前綴,自然也就能包含 \(L\)

線段樹上只維護 \(dfn,low\) 。複雜度 \(O((m+Q)\log m)\)

T3

挺有趣的一道題,可惜場上沒時間想。

稱 x-度點 表示有 \(x\) 個兒子的點。

subtask 1

在這檔部分分中,樹中不存在一度點。

容易發現詢問 \(V\backslash\{x\}\) 可以得到這個點是否是葉子,那麼先用 \(n\) 次操作得到此時的葉子集合。然後考慮怎麼確定葉子的父親,發現當 \(x\) 是葉子時可以詢問 \(V\backslash \{x,y\}\) 來確定 \(y\) 是否是 \(x\) 的父親。如果 \(fa_x=y\) 那麼會返回 \(n-2\) ,否則是 \(n-1\)

然後發現這個枚舉 \(y\) 的過程其實可以直接二分一個前綴,就可以在 \(O(\log n)\) 的時間內得到一個葉子的父親。發現兩個葉子的父親相同之後就可以刪掉這兩個葉子,並把它們的父親加入葉子集合。

這樣就獲得了一個 \(O(n\log n)\) 次詢問得到樹形態的做法。

subtask 2

此時樹中可能存在一度點,但詢問次數更多(當然數量級沒有變)。

考慮上面的做法,會發現在第一步就直接錯了:詢問 \(V\backslash \{x\}\) 並不能區分零度點和一度點。我們先把二度點區分出來,然後考慮零度點和一度點的集合 \(S\) 。那麼詢問 \(S\backslash \{x\}\) 會有兩種取值:

  • \(n-2\) :這個點是零度點,且它的父親是一度點。
  • \(n-1\) :這個點是一度點,或者它是零度點且它的父親是一度點。

容易發現如果出現 \(n-1\) 的第二種情況,那麼一定無法確定樹的形態。所以先不考慮這一種情況,求出三種點的數量 \(c_0,c_1,c_2\) 。由於真正的 \(c_0\) 應當等於 \(c_2-1\) ,所以如果不滿足這個條件就直接返回無法確定。

然後用 subtask 1 的做法先得到只考慮零度點和二度點的樹形態,然後嘗試把一度點塞進去。

然後又是一個性質:在二叉樹中,詢問一個點集,可以根據大小來判斷是否至少有一組 祖先-後代 關係。那麼選擇一個葉子集合 \(L_0\) 和一個一度點 \(x\) ,詢問 \(L_0\cup \{x\}\) 即可確定 \(x\) 的子樹中是否存在 \(L_0\) 中的葉子。如果總葉子集合是 \(L\) ,那麼詢問 \((L\backslash L_0)\cup\{x\}\) 就可以知道 \(x\) 子樹的葉子集合是否被 \(L\) 完全包含。

現在樹的基本形態已經確定了,所以可以邊分治,確定所有一度點是在這個子樹內,在外面,還是恰好在這條邊上。

出題人用神奇分析方法得到了詢問次數上界是 10408 ,不太懂怎麼做到的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章