你是大魚,你管理著一個巨大的國家。
這個國家之中有很多城市,城市之間也有很多河流。經過仔細的觀察發現,每個城市都會流出一條河流,要麼流向大海,要麼流向另外一座城市。由於水總是往低處流動,所以不會出現一個河流構成的環,而且你發現流向大海的河流只有一條。
在某一個時刻,可能會有一場暴雨在某座城市上空降臨,這座城市流出的河流會暴增,這座城市下游的城市流出的河流也都會暴增。
下暴雨的城市沒有什麼較好的防範辦法,但是在下游的每一座城市,它們都可以在流向它們的其中一條河流做好準備。如果一個城市在一條流向它的河流做好了準備,它就可以避免這條河流暴增造成的巨大損害。
在一開始,你可以命令每座城市在一條流向它的河流做好準備(當然也可以不做任何準備)。在之後的每場暴雨前後,由於時間緊急,所以你只能發出一些緊急命令。緊急命令有兩種:
- 令一座城市取消對流向它河流的準備。
- 令一座城市在某一條流向它的河流做好準備。
由於人力資源的原因,你並不能讓一座城市同時在兩條河流做好準備,因此如果你想讓一座已經在某條河流做好準備的城市在另一條河流做準備,你必須先取消它在當前河流的準備。
現在有 $q$ 場暴雨一場接著一場到來,你能在一場暴雨前觀測到它將在哪座城市降臨。在每場暴雨前你可以發出一些緊急命令來避免下游的城市受到巨大損害,你也可以在暴雨後發出一些緊急命令來做一些暴雨後的準備。當然,你希望發的緊急命令盡量少,你可以找到一個優秀的辦法嗎?
任務
你需要實現兩個函數,以完成題目的任務:
init(n, father):- 這個函數將在任務一開始運行,且僅會調用一次,它將會告訴你這座國家的一些資訊,你需要給出一開始每座城市做的準備。
n表示城市數量,城市編號為 $1$ 到 $n$。father是一個長度為 $n - 1$ 的陣列,下標為 $[0 \dots n-2]$,$father_i$ 表示城市 $i + 2$ 流出河流到達城市的編號,其中城市 $1$ 流出的河流流入大海,保證 $father_i < i + 2$。- 返回一個長為 $n$ 的陣列,表示每個城市一開始做出的準備,第 $i-1$ 個數表示第 $i$ 個城市一開始準備好來自這個城市的河流,若為 $0$ 則表示什麼都沒有準備。
solve(x):- 該函數可能會在調用
init函數之後被調用多次,表示一場暴雨即將在城市 $x$ 襲來,你需要使用set函數發出緊急命令來避免下游城市的巨大損害。 - 你需要保證在這個函數中調用
set函數次數不超過 $60$。 - 在這個函數中你應該調用
wait函數恰好一次,在調用wait函數之前的發出命令將在暴雨來臨前發出,在調用wait函數之後發出的命令將在暴雨來臨後發出。
- 該函數可能會在調用
你可以調用以下兩個函數來實現 solve。
set(x, p):- 僅可以在
solve函數中調用,表示讓 $x$ 城市在 $p$ 城市流出河流做好準備,如果 $p$ 為 $0$,那麼代表讓城市 $x$ 取消對流向他的河流的準備。 - 每次
solve時最多調用 $60$ 次。 - 禁止在
init函數中調用。
- 僅可以在
wait()- 在每次
solve時恰好調用一次,表示你完成了暴雨前的準備,調用時必須保證此時暴雨來臨該城市下游的城市都在流向它的河流做好準備。 - 該函數調用後可以繼續操作,為下次暴雨做準備。
- 禁止在
init函數中調用。
- 在每次
注意,一座城市要麼不做任何準備,要麼在一個城市到它的河流做好準備。
如果你的操作不合法或不滿足要求,該測試點將立刻得到 $0$ 分。
如果有不清楚的地方,見範例及評測庫下載,內附了範例程式。
實作細節
本題只支援 C++ 語言。
你只能提交一個原始碼檔案實現如上所述的 init、solve 函數,並且遵循下面的命名和介面。你需要包含標頭檔 river.h。
std::vector<int> init(int n, std::vector<int> father);
void solve(int x);
函數 set、wait 的介面資訊如下。
void set(int x, int p);
void wait();
範例
下發的範例評測系統將讀入一棵樹和所有操作,格式如下:
第一行輸入兩個正整數 $n,q$,表示樹的點數、詢問數。
第二行 $n-1$ 個數表示 father 陣列。
接下來 $q$ 行,每行一個數 $x$ 表示調用一次 solve(x)。
輸入範例 1
8 8 1 1 3 3 4 5 3 7 1 1 7 3 6 5 1
輸出範例 1
2 6 ok you are right!
說明 1
這是成功完成所有操作後給出的資訊,其中第一個正整數表示你一回合中調用 set 次數最大值,第二個是你調用 set 的次數總和。
資料範圍
$1\leq n \leq 50000$,$1 \leq q \leq 500000$。
你不能在一回合中調用超過 $60$ 次命令。
如果你在規定時間空間限制內沒有完成任務,你將獲得 $0$ 分。
不然,設 $x$ 為每次 solve 中調用 set 次數的最大值 $\max$,則你得到的分數為
$$ f \left( x \right) = \begin{cases} 0 & 60 \lt x \\ 100 - 18 \times \sqrt{x - 35} & 36 \leq x \leq 60 \\ 100 & \operatorname{otherwise} \end{cases} $$
你的分數將會是所有測試點中分數的最小值。
若每次 solve 中 set 的調用次數不超過 $60$,且所有操作合法的話:
保證互動庫用時不超過 $ 1\,\mathrm{s}$。
保證互動庫使用空間不超過 $ 10\,\mathrm{MB}$。