啟發式合併

2022-05-24 14:03:13 字數 1836 閱讀 7191

概念

啟發式演算法是基於人類的經驗和直觀感覺,對一些演算法的優化。

作用可以啟發式合併更加高階的資料結構,如 \(heap,~set,~splays\) 等

複雜度計算

每次把個數少的合併到個數多的?複雜度 \(o(min(m1,m2))\)

可是我們注意到,每次合併後個數為合併前少的部分的個數的兩倍以上,每個元素最多合併 \(logm\) 次,總複雜度 \(o(mlogm)\) 。

當合併 \(heap,~set,~splays\) 等,複雜度 \(o(mlog2m)\)(作者太弱,不會證明)

例題1[hnoi2009] 夢幻布丁

思路對於每乙個顏色,建一條鍊錶。然後染色就是把鏈短的合併到鏈長的。

需要注意細節,如果把2染成3,但2的鏈比3的長,就需要把3的合併到2上。但是現在本應屬於3的鏈在2上,就需要記乙個該顏色的鏈現在在哪個顏色上,即是**中的 \(now\) 陣列。

**

#include#define rep(i, a, b) for (register int i=(a); i<=(b); ++i)

#define per(i, a, b) for (register int i=(a); i>=(b); --i)

using namespace std;

void swap(int &x, int &y)

const int n=1000005;

int head[n], nxt[n], col[n], now[n], cnt[n], st[n], ans;

inline int read()

void merge(int x, int y)

for (int i=head[x]; i; i=nxt[i]) col[i]=y;

nxt[st[x]]=head[y]; head[y]=head[x];

head[x]=st[x]=cnt[x]=0;

}int main()

rep(i, 1, m)

}return 0;

}

例題2

[十二省聯考2019]春節十二響

思路考慮一條鏈,顯然你是把兩個鏈分別的最大值放在一起,次大值放在一起,等等

那麼如果有多個鏈呢?你就把第乙個鏈和第二個鏈按上面的操作,得到的新的結果再和第三個鏈合併...

**

#include#include#include#include#include#define ll long long

using namespace std;

const int maxn=2e5+5;

int a[maxn],id[maxn],tot,tp[maxn];

priority_queueq[maxn];

inline int read()

while(isdigit(ch))

return x*f;

}struct edgee[maxn<<1];

int head[maxn],cnt;

void add(int u,int v)

inline void dfs(int now,int fa)

for(int j=1;j<=size;j++) q[id[now]].push(tp[j]);

} q[id[now]].push(a[now]);

}int main()

dfs(1,0);

ll ans=0;

while(q[id[1]].size()) ans+=q[id[1]].top(),q[id[1]].pop();

printf("%lld",ans);

return 0;

}

啟發式合併

啟發式合併 暴力合併 將兩個資料結構合併,只需要將小的資料結構中的元素乙個乙個的插入大的資料結構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 不能接受。可以觀察到,合併的時間複雜度只與被合併的鏈長度有關,所以可以想到優化...