lca倍增演算法學習記錄
找最近公共父節點這問題很容易想到讓兩節點一起往上走最後相遇,但這樣的dfs顯然很慢,於是就需要倍增。就是用二進位制的思維,以1,2,4,8等2的階層步長接近答案,比一步一步向上要快很多。
所以要dfs出來點的2^k的父親節點與該節點的深度。
找lca時先將下面的點升到與另一點同一深度,再用往上倍增找lca。
有兩種大同小異的方法:一種是以上一步2倍長的步伐向上試,不行再縮減,找到一個離lca能達到的最近點。另一種是先求出最大深度是2的幾次方,再以當前最大步伐向上走。具體看下面程式碼,喜歡哪種打哪種。。。
簡單一題hdu2586
大意是求兩節點距離,只用在dfs時求從根到節點的距離,用L=dis[i]+dis[j]-2*dis[lca(i+j)]求出。
以下程式碼:
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=40005;
int tot;
int a[maxn],b[maxn*2],c[maxn*2],w[maxn*2],deep[maxn],dis[maxn],fa[maxn][16]; //注意邊要兩倍空間
bool bo[maxn];
void setin(int x,int y,int z) //鄰接表儲存圖
{
b[++tot]=a[x];
a[x]=tot;
c[tot]=y;
w[tot]=z;
}
void dfs(int x) //預處理
{
int p,son;
p=a[x];
while(p)
{
son=c[p];
if(!bo[son])
{
bo[son]=true; //避免走回去
fa[son][0]=x;
deep[son]=deep[x]+1;
dis[son]=dis[x]+w[p];
int ii=0,po=x;
while(fa[po][ii]!=0)
{
fa[son][ii+1]=fa[po][ii];
po=fa[po][ii++]; //關鍵!父節點相當於每次*2,來更新這個子節點的2^k父節點,自己模擬就明白了
}
dfs(son);
}
p=b[p];
}
}
int lca(int x,int y)
{
if(x==y) return x;
if(deep[x]<deep[y]) swap(x,y);
int m=deep[x]-deep[y],ii=0;
while(m) //m表示為二進位制,以2,4,8等步伐向上
{
if(m&1==1) x=fa[x][ii];
m>>=1;
ii++;
}
ii=0;
while(x!=y)
if(fa[x][ii]!=fa[y][ii]||((fa[x][ii]==fa[y][ii])&&(ii==0))) //條件很關鍵,僅有一步時要走才能退出迴圈
{
x=fa[x][ii];
y=fa[y][ii];
ii++;
}
else ii--;
return x;
}
int main()
{
int t,n,q,x,y,z;
scanf("%d",&t);
for(int i=0;i<t;i++)
{
tot=0;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
memset(w,0,sizeof(w));
memset(deep,0,sizeof(deep));
memset(dis,0,sizeof(dis));
memset(fa,0,sizeof(fa));
memset(bo,0,sizeof(bo));
scanf("%d%d",&n,&q);
for(int j=0;j<n-1;j++)
{
scanf("%d%d%d",&x,&y,&z);
setin(x,y,z);
setin(y,x,z);
}
deep[1]=1;
dis[1]=0;
bo[1]=true;
dfs(1);
for(int j=0;j<q;j++)
{
scanf("%d%d",&x,&y);
printf("%d\n",dis[x]+dis[y]-2*dis[lca(x,y)]);
}
}
}
另一種lca求法:
int lca(int x,int y)
{
int i,j;
if(deep[x]<deep[y])swap(x,y);
for(i=0;(1<<i)<=deep[x];i++); //求深度是2的幾次方,給下面迴圈找上界
i--;
for(j=i;j>=0;j--)
if(deep[x]-(1<<j)>=deep[y])
x=fa[x][j]; //另一種將x提到與y同高度的寫法
if(x==y)return x;
for(j=i;j>=0;j--)
{
if(fa[x][j]!=fa[y][j])
{
x=fa[x][j];
y=fa[y][j];
}
}
return fa[x][0]; //注意是把2^k拆成1和其他2的次方,所以返回父節點
}
ps:因為並不會vector釋放記憶體,就寫了一大串memset,求大神指教如何簡化。
相關推薦
lca倍增演算法學習記錄
找最近公共父節點這問題很容易想到讓兩節點一起往上走最後相遇,但這樣的dfs顯然很慢,於是就需要倍增。就是用二進位制的思維,以1,2,4,8等2的階層步長接近答案,比一步一步向上要快很多。 所以要dfs出來點的2^k的父親節點與該節點的深度。 找lca時先將下
演算法學習記錄
2018.10.17 二維凸包 2018.10.18 樹形DP 2018.10.20 矩陣乘法 2018.10.25 單源最短路,最小生成樹 2018.10.26 並查集,區間DP 2018.11.2 樹狀陣列,無懶標記線段樹 2018.11.4 單調佇列,狀態壓縮DP,網路最大流 2018.11.5 優先佇
lca倍增演算法模板
1431: LCA 最近公共祖先 時間限制: 1 Sec 記憶體限制: 128 MB提交: 244 解決: 36 [提交][狀態] 題目描述 給一棵樹, 節點數為N(1 <= N &
lca倍增演算法
HDU2586 要注意只有簡單邊相連的圖是一棵樹,樹有n-1條邊 倍增之前要先存雙向邊,以任意頂點為根(比如1)dfs遍歷確定樹。 倍增前求f[i,j]時先賦值為-1便於判斷f[ij-1]祖先存不存在 倍增時先將兩個點調至同一高度(注意最後的微調每次只上升一個高度) pro
LCA-Tarjan,RMQ,倍增演算法超詳細原理講解+python實踐(Lowest Common Ancestor of a Binary Tree)
最近公共祖先演算法: 通常解決這類問題有兩種方法:線上演算法和離線演算法 線上演算法:每次讀入一個查詢,處理這個查詢,給出答案 離線演算法:一次性讀入所有查詢,統一進行處理,給出所有答案 我們接下來介紹一種離線演算法:Tarjan,兩種線上演算法:RMQ,倍增演算法 Tarjan
最近公共祖先(LCA) 【倍增演算法】
題目連結:洛谷-P3379 ## **題目描述**: 如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。 思路 這是一個裸的LCA問題,即求書上兩個節點的最近公共祖先。 我們可以用樹上倍增來做; 當然,在做之前我們假設不知道該演算法。那麼我們如何來做
資料結構與演算法——學習整理記錄
===注:此文由本人結合網上資源整理總結而來,僅代表個人的學習與理解,如有錯漏,歡迎指正!=== # 1. 資料結構 ## 1.1 資料結構是什麼? 資料結構,直白地理解,就是研究資料的邏輯關係與儲存方式的一門學科。 可以簡單的分為:資料的邏輯結構(邏輯關係)和資料的儲存結構(物理結構
【資料結構與演算法經典問題解析--java語言描述】_第20、21章_學習記錄
【資料結構與演算法經典問題解析--java語言描述】_第20、21章_學習記錄 第20章: 第21章: 1.1 本章主要介紹的是對於面試和考試有用的話題 1.2 位運算的使用 1.2.1 按位與操作
Pow(x, n)演算法實現_學習記錄
pow(x, n)演算法實現_學習記錄 package ps; /** * @author Guozhu Zhu * @date 2018/11/10 * @version 1.0 * */ public class Demo { /* ===========
DP之倍增演算法解決LCA問題
LCA,最近公共祖先,也就是樹上兩個節點的相同的祖先裡距離它們最近的(也就是深度最深的)。倍增演算法用於解決LCA問題的線上查詢。 比如要找x和y的LCA,一般會怎麼做? 首先是暴力。一種是DFS遍歷說有點,無需預處理,查詢是O(n)的。還有一種暴力是先一步一步將x和y提到同一高度,然後
密碼庫LibTomCrypt學習記錄——(2.3)分組密碼演算法的工作模式——ECB程式碼示例
以下程式碼實現了AES-ECB的正確性測試(標準測試資料),以及效能測試 說明: 1. 程式碼裡面使用了一個Str2Num函式,它將測試向量中的字串轉為十六進位制位元組資料,可自行實現。 2. 測試向量出處為NIST SP 800-38A (Recommendation for Bloc
[HDU2586] How far away ?{LCA.tarjan演算法/倍增演算法}
文章目錄 題目 解題思路 程式碼`倍增(TLE)` 程式碼`tarjan演算法(AC)` $tanjan$演算法本質上是使用並查集對“向上標記法”的優化 題目 http://acm.hdu.edu.cn
【資料科學系統學習】機器學習演算法 # 西瓜書學習記錄 [7] 支援向量機(一)
這兩篇內容為西瓜書第 6 章支援向量機 6.1,6.2,6.4,6.3 的內容: 6.1 間隔與支援向量 6.2 對偶問題 6.4 軟間隔與正則化 6.3 核函式 由於本章內容較多,分為兩篇來敘述。本篇所包含內容為間隔與支援向量和對偶問題。 如移動端無法正常
【資料科學系統學習】機器學習演算法 # 西瓜書學習記錄 [8] 支援向量機(二)
這兩篇內容為西瓜書第 6 章支援向量機 6.1,6.2,6.4,6.3 的內容: 6.1 間隔與支援向量 6.2 對偶問題 6.4 軟間隔與正則化 6.3 核函式 由於本章內容較多,分為兩篇來敘述。本篇所包含內容為軟間隔與正則化和核函式。關於間隔與支援向量和
【資料科學系統學習】機器學習演算法 # 西瓜書學習記錄 [9] 決策樹
本篇內容為西瓜書第 4 章決策樹 4.1,4.2,4.3 的內容: 4.1 基本流程 4.2 劃分選擇 4.3 剪枝處理 如移動端無法正常顯示文中的公式,右上角跳至網頁即可正常閱讀。 決策樹 (decision tree) 是一種基本的分類與迴歸方法。在分類問
【資料科學系統學習】機器學習演算法 # 西瓜書學習記錄 [10] 決策樹實踐
本篇內容為《機器學習實戰》第 3 章決策樹部分程式清單。所用程式碼為 python3。 決策樹優點:計算複雜度不高,輸出結果易於理解,對中間值的缺失不敏感,可以處理不相關特徵資料。缺點:可能會產生過度匹配問題。適用資料型別:數值型和標稱型 在構造決策樹時,我們需要
【資料科學系統學習】機器學習演算法 # 西瓜書學習記錄 [11] 整合學習
本篇內容為西瓜書第 8 章整合學習 8.1 8.2 8.3 8.4 8.5 的內容: 8.1 個體與整合 8.2 Boosting 8.3 Bagging與隨機森林 8.4 結合策略 8.5 多樣性 如移動端無法正常顯示文中的公式,右上角跳至網頁即可正常閱讀。
【資料科學系統學習】機器學習演算法 # 西瓜書學習記錄 [12] 整合學習實踐
本篇內容為《機器學習實戰》第 7 章利用 AdaBoost 元演算法提高分類效能程式清單。所用程式碼為 python3。 AdaBoost優點:泛化錯誤率低,易編碼,可以應用在大部分分類器上,無引數調整。缺點:對離群點敏感。適用資料型別:數值型和標稱型資料。 bo
機器學習實戰----kNN近鄰演算法問題記錄
1.import kNN。報錯:only 2 non-keyword arguments accepted 原因:group =array([1.0,1.1],[1.0,1.0],[0,0],[0,0.1]) 粗心少寫了兩個中括號 正確寫法: group=array([
關於CNN行為識別演算法的學習記錄
最近需要做一點行為識別相關的專案,於是把行為識別類的演算法(特別是基於CNN的演算法)調研了一遍。 到目前為止,CNN行為識別類的演算法主要都是基於雙流和3D卷積兩種方法,近年來,融合使用光流和C3D的演算法逐漸增多(I3D),也有的演算法使用瞭如RGB Diffieren