1. 程式人生 > 實用技巧 >NOI2019 I 君的探險

NOI2019 I 君的探險

I 君的探險

地下宮殿可以抽象成一張 \(N\) 個點、\(M\) 條邊的無向簡單圖(簡單圖滿足任意兩點之間至多存在一條直接相連的邊),洞穴從 \(0 \sim n − 1\) 編號。目前你並不知道邊有哪些。

每個洞穴都擁有一個光源,光源有開啟、關閉兩種狀態,只有當光源處於開啟狀態時它所在的洞穴才會被照亮。初始時所有的光源都處於關閉狀態,而光源的狀態只能用 I 君發現的神祕機關改變。更具體的,使用神祕機關可以進行如下四種操作:

  1. 向機關給定一個編號 \(x\),機關將會改變 \(x\) 號洞穴,以及與 \(x\) 號洞穴有通路直接相連的洞穴的光源狀態。即原來開啟的光源將會關閉;原來關閉的光源將會開啟。

  2. 向機關給定一個編號 \(x\),機關將會顯示當前 \(x\) 號洞穴光源的狀態。

  3. 向機關給定兩個編號 \(x, y\),表示你確定有一條連線 \(x\) 號洞穴與 \(y\) 號洞穴的通路,並讓機關記錄。

  4. 向機關給定一個編號 \(x\),機關將會判斷與 \(x\) 號洞穴相連的通路是否都已被記錄。

機關在完成上一次操作後才能進行下一次操作。機關不能隨意使用,因此每種操作的使用次數都有限制,分別為 \(L_m, L_q, M, L_c\)。你的任務是,編寫一個程式,幫助 I 君決定如何合理利用神祕機關,從而正確地找到這 \(M\) 條通路。

https://uoj.ac/problem/483

題解

將分部分分進行介紹。

測試點1~5

修改\(x\)之後查詢\(x+1\sim N\)有沒有變化即可。\(n-1\)次modify,\(\binom{N}{2}\)次query。

測試點6~9

使用分治。對當前集合內的點挨個掃描,亮了不管,沒亮點亮,直到亮了\(\frac{N}{2}\)個為止。

這樣集合就被分成了亮了的和沒亮的兩部分,分別遞迴處理即可。

\(N\log_2N\)次modify和query。

有一種更簡單的方法,那就是以\(\frac{1}{2}\)的概率修改每個點。這樣一對匹配點亮了和沒亮的概率都是\(\frac{1}{2}\),複雜度相同。

測試點10~11

由於父節點編號小於子節點,所以對於單個節點\(x\)

來說可以二分他的父節點。把\([1,mid]\)中的點都修改一遍然後查詢一下\(x\)的狀態就能確定\(x\)的父節點在不在\([l,mid]\)中。

對所有節點考慮,整體二分即可。

\(N\log_2N\)次modify和query。

測試點12~17

在無環圖上,我們希望用一種“剝葉子”的過程,通過逐步刪去度數為\(1\)的點,最後找到整個圖的形態。

我們不妨記每個點的標號為\(1\sim N\),對每個\(k∈[1,\log_2N]\),我們把二進位制下第\(k\)位為\(1\)的點拿出來MODIFY,然後QUERY全體點

  • 在這個操作下,\(x\)號點顏色改變,當且僅當\(x\)關聯了奇數個第\(k\)位為\(1\)的點

不難發現,對每個\(k\)做一遍這個過程後,我們可以得知每個點關聯的全體點的標號異或和。顯然這個過程花費\(N\log_2 N\)次MODIFY和QUERY

現在,記\(sum[i]\)\(i\)關聯的全體點(不包括自己)的異或和,考慮一個點\(x\)

  • \(x\)度數為\(1\),那麼\(sum[x]\)\(x\)恰好有一條邊

  • 通過兩次QUERY、一次MODIFY,可以判定是否存在一條\(sum[x]\)\(x\)的邊

  • 若存在這樣一條邊,可以令\(sum[sum[x]]=sum[sum[x]]⊕x\)以及\(sum[x]=0\),然後“斷開”這條邊

造一個佇列\(Q\),初始時每個點都在其中,每次從\(Q\)中取出一個點\(x\),檢查\(x\)\(sum[x]\)之間是否有一條邊

  • 若是,把\(sum[