爬山 啟發式合併 STL

2022-06-01 19:36:08 字數 2111 閱讀 5084

其實 kano 曾經到過由乃山,當然這名字一看山主就是 yuno 嘛。當年 kano 看見了由乃山,內心突然湧出了一股杜甫會當凌絕頂,一覽眾山小的豪氣,於是毅然決定登山。

但是 kano 總是習慣性亂丟垃圾,增重環衛工人的負擔,yuno 並不想讓 kano 登山,於是她果斷在山上設定了結界……

yuno 為了方便登山者,在山上造了 n 個營地,編號從 0 開始。當結界發動時,每當第 i(>0)號營地內有人,那麼他將被傳送到第 ai(但 kano 並不知曉結界的情況。他登山的方法是這樣的:首先分身出乙個編號為 gi 的 kano,然後將其用投石機拋擲到營地 di。kano 總共做了 m 次這樣的登山操作,但每次丟擲去的 kano 都被傳送回了營地 0,所以 kano 只好放棄了。

但是 kano 在思考乙個問題,到底每個營地被多少只編號不同的 kano 經過過?

第一行兩個整數 n,m,表示山的營地數和登山次數。

接下來 n−1 行,每行乙個數,第 i 行為 ai,表示營地 i 將會傳向營地 ai。

接下來 m 行,每行兩個數 di,gi。

共 n 行,每行表示營地 i 有多少不同編號的 kano 曾經通過。

input

5 400

114 13 1

2 24 2

output
221

12

樣例解釋

1 號 kano 曾被拋到 3,4 兩個營地,傳送軌跡分別是 3−1−0, 4−1−0

2 號 kano 曾被拋到 2,4 兩個營地,傳送軌跡分別是 2−0, 4−1−0

所以 0,1,4 號營地被兩隻 kano 經過過,2,3 號營地被乙隻 kano 經過過。

\(5≤n≤100000,10≤m≤100000,max(gi)≤1000000000\)

時間限制:1s

空間限制:512mb

首先來想一想本題的暴力解法.

很直觀的思路是對每乙個營地用陣列(或\(vector\)/\(set\)/\(queue\)/線段樹/平衡樹)維護乙個集合,存放到達過該點的\(kano\)的編號.當第\(i\)號營地裡的\(kano\)被傳送到第\(a_i\)號營地時,把維護的第\(i\)號營地的集合合併到第\(a_i\)號營地的集合裡.最後,每個營地的集合去重後的大小,就是曾經經過了該營地的不同編號的\(kano\)的數量.

這樣就有兩個問題:一是合併的順序;二是怎麼合併兩個資料結構.

第乙個問題很好回答:我們可以倒序從\(n\)到\(1\)遍歷序列,每次計算出該營地的答案,同時把該營地的資料合併到\(a_i\)營地.這是因為\(a_i,也就是說,無論哪次合併,都是"從後面的某個營地合併到前面的某個營地".換句話說,乙個營地的狀態,只與它和它後面的某些營地有關.

第二個問題也很好回答,只需要按照啟發式合併的思想,每次都將小的集合合併到大的集合,這樣可以獲得優秀的\(o(nlog_2n)\)的時間複雜度.

在**實現中我使用了\(stl-set\),以省去去重的環節.

#include#includeusing namespace std;

int n,a[100005],m,g,d,ans[100005],id[100005];

setx[100005];

inline void merge(int u,int v)

int main()

for(int i=1;i<=n;i++)id[i]=i;

while(m--)

for(int i=n;i;i--)//將 i 合併到 a[i]

for(int i=1;i<=n;i++)printf("%d\n",ans[i]);

return 0;

}

如果把題給的條件看成\(\)的有向邊,那麼可以建出乙個\(dag\)圖,而上面提到的倒序從\(n\)到\(1\)就是該圖的乙個拓撲序,因此我們可以倒著合併.

啟發式合併

啟發式合併 暴力合併 將兩個資料結構合併,只需要將小的資料結構中的元素乙個乙個的插入大的資料結構o n o n o n 如果題目只有插入操作沒有 總o n logn o nlogn o nlog n 因為每次合併,所有資料結構總大小為n,設兩個資料結構大小為a,b a b a,b a b a,b a...

啟發式合併

includeconst int n 5e5 5 int f n d n r n p n int find int i int unionn int i,int j int main 並查集 按秩啟發式合併 bzoj4668 冷戰 題目大意 給出n個軍工廠和m 個操作,操作分為兩類 0 u v,這次...

啟發式合併

啟發式合併本質上是一種優化的暴力,可用於擁有穩定結構的資料結構。考慮夢幻布丁 hnoi2009 顯然的暴力思路是用鍊錶維護每種顏色的位置,然後每次修改的時候暴力合併兩條鏈。不難證明,這樣的最壞時間複雜度將達到 o n 2 不能接受。可以觀察到,合併的時間複雜度只與被合併的鏈長度有關,所以可以想到優化...