Tarjan求LCA

來源:互聯網
上載者:User

標籤:getc   namespace   記錄   getch   很多   amp   代碼   read   typedef   

LCA問題算是一類比較經典的樹上的問題

做法比較多樣

比如說暴力啊,倍增啊等等

今天在這裡給大家講一下tarjan演算法!

tarjan求LCA是一種穩定高速的演算法

時間複雜度能做到預先處理O(n + m),查詢O(1)

它的主要思想是dfs和並查集

1.輸入資料,找出根節點(或輸入的)並將圖存起來

2.輸入需要尋找的每一對點(兩個點),也存起來(也存成圖)

3.從根節點開始向它的每一個孩子節點進行深搜

4.同時開一個bool類型的數組記錄此節點是否搜尋過

5.搜尋到p節點時先將p標記為已經搜尋過了

6.然後遍曆所有與p相連的節點,並標記為已經搜尋過了

7.接著將p的子節點和p合并(此處要用到並查集)

8.然後遍曆所有和p有詢問關係的p的子節點

9.若該子節點已經遍曆過,則一定可以將該子節點和p的父親節點合并

可能還是有很多人並沒有完全理解這段文字敘述的演算法過程

下面就直接上代碼(注釋很詳細)

#include<cstdio>#include<cstring>#include<cstdlib>#include<cctype>#include<cmath>#include<string>#include<iostream>#include<algorithm>#include<map>#include<set>#include<queue>#include<stack>#include<vector>using namespace std;typedef long long ll;const int maxn = 5e5 + 5;int read(){    int ans = 0, op = 1;    char ch = getchar();    while(ch < ‘0‘ || ch > ‘9‘)    {        if(ch == ‘-‘) op = -1;        ch = getchar();    }    while(ch >= ‘0‘ && ch <= ‘9‘)    {        ans *= 10;        ans += ch - ‘0‘;        ch = getchar();    }    return ans * op;}struct Drug{    int next, to, lca;}edge[maxn<<1], qedge[maxn<<1];//edge[N]為樹的鏈表;qedge[N]為需要查詢LCA的兩節點的鏈表int n, m, s, x, y;int num_edge, num_qedge, head[maxn], qhead[maxn], father[maxn];bool visit[maxn];//判斷是否被找過 void add_edge(int from, int to)//建立樹的鏈表 {    edge[++num_edge].next = head[from];    edge[num_edge].to = to;    head[from] = num_edge;//    printf("#%d #%d #%d #%d\n", num_edge, head[from], from, edge[num_edge].next);}void add_qedge(int from, int to)//建立需要查詢LCA的兩節點的鏈表 {    qedge[++num_qedge].next = qhead[from];    qedge[num_qedge].to = to;    qhead[from] = num_qedge;}int find(int x)//找爹函數 {    if(father[x] ^ x) father[x] = find(father[x]);    return father[x];}void dfs(int x)//把整棵樹的一部分看作以節點x為根節點的小樹, x的初始值為s; {    father[x] = x;//由於節點x被看作是根節點,所以把x的father設為它自己     visit[x] = 1;//標記為已被搜尋過     for(int k = head[x]; k ; k=edge[k].next)//遍曆所有與x相連的節點     {        if(!visit[edge[k].to])//若未被搜尋         {            dfs(edge[k].to);//以該節點為根節點搞小樹             father[edge[k].to] = x;//把x的孩子節點的father重新設為x         }    }    for(int k = qhead[x]; k ; k = qedge[k].next)//搜尋包含節點x的所有詢問     {        if(visit[qedge[k].to])//如果另一節點已被搜尋過         {            qedge[k].lca = find(qedge[k].to);            //把另一節點的祖先設為這兩個節點的最近公用祖先             if(k & 1) qedge[k + 1].lca = qedge[k].lca;            //由於將每一組查詢變為兩組,所以2n-1和2n的結果是一樣的            else qedge[k - 1].lca = qedge[k].lca;        }    }}int main(){    n = read(), m = read(), s = read();//輸入節點數,查詢數和根節點     for(int i = 1;i < n;i++)    {        x = read(), y = read();//輸入每條邊         add_edge(x, y);        add_edge(y, x);    }    for(int i = 1;i <= m;i++)    {        x = read(), y = read();        //輸入每次查詢,考慮(u,v)時若尋找到u但v未被尋找,所以將(u,v)(v,u)全部記錄         add_qedge(x, y);        add_qedge(y, x);    }    dfs(s);     for(int i = 1;i <= m;i++) printf("%d\n", qedge[i << 1].lca);//兩者結果一樣,只輸出一組即可//    printf("%d", num_edge);     return 0;}

 

 

 

 

Tarjan求LCA

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.