1.1.2 思路:設d[x]為從結點x出發走以x為根的子樹,能夠達到最遠結點的距離。設x的子節點為y1,y2,y3...yt,edge(x,yi)表示邊的權重,那就有:d[x] = max(i <= i <=t)。
接下來設經過x的最長鏈的長度為f[x],那麼整棵樹的直徑就是max (1 <= x <= n)。f[x]可以由四個部分構成:x走yi子樹的最遠距離,x走yj子樹的最遠距離,x到yi的距離,x到yj的距離。也就是:f[x] = maxn。
由於我們已經用d[x]儲存從結點x出發走向 「以yj為根的子樹(j < i)」 ,能夠達到的最遠距離,這個距離就是max。所以,我們只要先用d[x] + d[yi] + edge(x,yi)來更新f[x],再用d[yi] + edge(x,yi) 來更新d[x]即可。
1.2.1 思路:通過兩次bfs求出樹的直徑,更容易計算出直徑上的具體結點。做法包括兩步:
從任意乙個節點出發,通過bfs或dfs對樹進行一次遍歷,求出與出發點距離最遠的節點記為p
從節點p出發,通過bfs或dfs再進行一次遍歷,求出與p距離最遠的節點,記為q
那麼p到q的路徑就是樹的一條直徑。因為p一定是直徑的一端,而同理q也是樹的另一端,故演算法成立。
1.2.2 **示例:
#include#include#include#include#includeusing namespace std;
const int maxn = 100005;
vectorg[maxn];//用來存放有向邊
int d[maxn];//存放從起始點到該節點的距離
int p[maxn];//父節點
bool vis[maxn];//是否已訪問
int bfs(int s)
if(d[x] > maxlen)
} return ans;//返回最大距離的結點編號
}
給定一顆有根樹,若節點z既是節點x的祖先,也是節點y的祖先,則稱z是x,y的公共祖先。在x,y所有的公共祖先中,深度最大的乙個稱為x,y的最近公共祖先,記為lca(x,y)。
2.2.1 思路:
從x向上走到根節點,並標記所有經過的節點
從y向上走到根節點,當第一次遇到已標記的節點時,就找到了lca(x,y)
2.2.2 複雜度分析:最壞為o(n)
2.3.1 模板:最近公共祖先模板
2.3.2 複雜度分析:每次詢問複雜度為o(logn)
2.4.1 模板:
2.4.2 複雜度分析:離線演算法,需要把m次詢問一次性讀入,統一輸出。時間複雜度o(n+m)
《演算法競賽高階指南——李煜東》p341
樹的最近公共祖先
做了一些二叉樹的題,發現二叉樹的查詢問題一般都是從左右子樹遞迴去解決,也往往都能得到答案,因此,這道題可以考慮是否能從左右子樹進行遞迴去解決呢?首先,要想通過遞迴來實現,就需要先確定臨界條件,那麼臨界條件是什麼呢?換句話說,臨界條件就是遞迴中能夠直接返回的特殊情況,第一點則是最常見的 判空 判斷根結...
0x61 樹的直徑與最近公共祖先(一)
1 樹的直徑 樹中最遠兩個節點之間的距離為樹的直徑,連線這兩點的路徑被稱為樹的最長鏈。樹的直徑一般有兩種求法,時間複雜度都是o n 我們假設樹以n個點n 1條邊的無向圖形式給出,並儲存在鄰接表 鏈式前向星 中。演算法1 樹形dp求樹的直徑 不妨設1號節點為根,設d x 表示從節點x出發向以x為根的子...
最近公共祖先 python 最近公共祖先
lca演算法樸素演算法 也就是我們所說的暴力演算法,大致的思路是從樹根開始,往下迭代,如果當前結點比兩個結點都小,那麼說明要從樹的右子樹中找 相反則從左子樹中查詢 直到找到乙個結點在當前結點的左邊,乙個在右邊,說明當前結點為最近公共祖先,如果乙個結點是另外乙個結點的祖先,那麼返回前面結點的父親結點即...