倍增我是真滴不會
倍增法(英語:binary lifting),顧名思義就是翻倍。
能夠使線性的處理轉化為對數級的處理,大大地優化時間複雜度。
(ps:上次學倍增lca,沒學會,老老實實為了嚴格次小生成樹滾回來重新學)
st表\(n~log(n)~\)的預處理與\(o~(1)\)的查詢
感性理解一下
對於每次詢問\([l,~r]\)
q:這裡為什麼不能直接用\(f_\) 呢?
a:因為我們這裡的\(log\)是向下取整的,可能會出現有一塊取不到的部分
q:那有重複的部分怎麼辦吶??
a:重複部分對答案的貢獻有影響嗎?
q:貌似莫得影響
a:\(ans = max(f_, f_)\)
注意點
\[log_2 1 = 0
\]\[log_2 x = log_2 \frac + 1
\]第二個式子是這樣推導出來的
\[log_2~x = log_2~2\times\frac\\
~~~~~~~~~~~~~~~= log_2 + log_2\frac\\
~~~~~~~~~=1+log_2\frac
\]code
#include #include #include #include #include #define ll long long
using namespace std;
const int logn = 22;
const int n = 2000001;
int read()
int log[n];
int n ,m;
void pre()
int f[n][25];
int main()
system("pause");
return 0;
}
倍增求lca
例題可以每次找深度比較大的那個點,讓它向上跳。顯然在樹上,這兩個點最後一定會相遇,相遇的位置就是想要求的 lca。 或者先向上調整深度較大的點,令他們深度相同,然後再共同向上跳轉,最後也一定會相遇.(摘自oi wiki)
就是從深度深的向上跳,到達同一深度後一起向上跳(學過樹剖的都知道吧,艹估計沒人跟我一樣先學的樹剖,然後回來學倍增)
倍增就很優秀了
dfs
void dfs(int x, int fa)
}
這一塊可以解釋一下,假如說求的是最下面兩個節點,很明顯兩個點的lca是紫線所指向的點,問題是怎麼找,\(\text\) 迴圈從大的向小遍歷,可以發現先從\(紅線 \to 粉線 \to 藍線 \to\)到了藍線所指的點,會向上跳一次到了紫線就發現了lca
\(\text \) 就是答案
這種是較為樸素倍增的求法,沒有用\(log\)優化
加入log優化的(但好像沒太大的常數優化)
log陣列還是原來的求法
void dfs(int x, int fa)
有一說一,我不大喜歡這種優化的方法我最喜歡的還是樹剖
#include #include using namespace std;
const int n = 5e5 + 10;
struct tree e[n << 1];
int nume, head[n];
void add_edge(int from, int to)
int dep[n], f[n][21];
void dfs(int u, int fa)
}int lca(int x, int y)
if (x == y)
return x;
for (int i = 20; i >= 0; i--)
return f[x][0];
}int main()
dfs(s, 0);
for (int i = 1, x, y; i <= m; i++)
}
#include #include #include #include #include #define ll long long
using namespace std;
const int n = 5e5 + 10;
int read()
struct edge e[n << 1];
int head[n], nume;
void add_edge(int from, int to)
int f[n][25], log[n], dep[n];
void dfs(int x, int fa)
}int lca(int x, int y)
return f[x][0];
}int main()
log[1] = 0;
for (int i = 2; i <= n; i++)
log[i] = log[i / 2] + 1;
dfs(s, 0);
for (int i = 1; i <= m; i++)
system("pause");
return 0;
}
#include #include using namespace std;
const int n = 5e5 + 10;
int head[n], nume;
struct node e[n << 1];
void add_edge(int from, int to)
int fath[n], siz[n], dep[n], son[n];
void dfs(int x, int fa)
}int dfn[n], pre[n], top[n], cnt;
void dfs2(int x, int tp)
}int lca(int x, int y)
if (dep[x] < dep[y])
swap(x, y);
return y;
}int n, m, s;
int main()
dfs(s, 0), dfs2(s, s);
for (int i = 1; i <= m; i++)
return 0;
}
LCA 倍增 學習小結
lca問題,即lowest common ancestor 最近公共祖先 lca問題有很多解法,比如 暴力解法 分塊解法 倍增演算法 tarjan演算法 lct演算法 在這裡呢,我們只討論倍增 倍增演算法其實是一種類似於dp的實現 pa i j p a i j 表示i號節點的2j 2 j個父親 pa...
倍增法與st
一篇部落格 最常用,也是最簡單的演算法,實質就是直接對暴力使用倍增優化將複雜度降低達到需求。有樹上的倍增和區間的倍增 depth 為每個節點的深度,fa i j i節點的 2 j 的父親。lg i log 2 1 const int maxn 5000001 int depth maxn fa ma...
倍增LCA複習
時間過去了如此之久,我連倍增lca都不怎麼記得了,要粗事啊。首先預處理層數和每個節點的父親,然後預處理p陣列,p i,j 表示i向上第2 j個祖先。最後對於每個詢問x,y先把x,y變成同一層數的 x或y向上走直到兩個層數相等 然後x,y同時向上走,直到x和y的父親相同位置。自 1.dfs預處理出所有...