1. 程式人生 > >Tarjan之求LCA

Tarjan之求LCA

算法 get ios nbsp read 而在 hid 統一 turn

Tarjan之求LCA

不要問我為什麽寫完Tarjan還要再補一句“求LCA的那個”

因為只說Tarjan的話完全不知道你指的是哪個算法……

勞模Tarjan同誌證明了好多算法,而且全都叫Tarjan算法(是不會起名了嗎x)

這個Tarjan是一個求LCA的離線算法

關於什麽是在線什麽是離線……

所謂的在線算法就是實時性的,比方說,給你一個輸入,算法就給出一個輸出,就像是http請求,請求網頁

一樣。給一個實時的請求,就返回給你一個請求的網頁。而離線算法則是要求一次性讀入所有的請求,然後在

統一處理。而在處理的過程中不一定是按照請求的輸入順序來處理的。說不定後輸入的請求在算法的執行過程

中是被先處理的。”

↑從網上抄來的w↑感覺很好懂……

因為是離線做法,重新排列了一下解決詢問的順序,所以要比在線算法快

Tarjan的前置技能是dfs和並查集,不會的趕緊去學x

那麽正片開始!

因為這是個離線算法,所以讀進來各條邊之後繼續讀進來所有詢問並存起來

然後從根開始dfs

訪問到每個點的時候,先遍歷從這個點u出去的所有邊,dfs未訪問過的點v,訪問後把這個點並到u的並查集上

然後掃一遍和u有關的所有詢問及其涉及到的點v

如果點v已經被訪問過了,那麽說明u和v的LCA已經算好了

真相只有一個,LCA就是點v所在的並查集的祖先

趕緊存進答案數組裏……

全部dfs完成後,答案也全部算完了,按詢問序輸出答案就OK了

具體實現可以看代碼OvO

技術分享
//Tarjan lca 
#include<iostream>
#include<cstdio>
using namespace std;
const int N=500009;
int n,m,s,cnt,tot,ep[N],qp[N],fa[N];
bool vis[N];
struct edge{
       int to,nex;
}e[N<<1];
struct query{
       int to,nex,ans;
}q[N<<1];
int read()
{
    int an=0;
    char
ch=getchar(); while(!(0<=ch&&ch<=9))ch=getchar(); while(0<=ch&&ch<=9){an=an*10+ch-0;ch=getchar();} return an; } int found(int x) { if(x==fa[x])return x; return fa[x]=found(fa[x]); } void adde(int u,int v) { ++cnt; e[cnt].to=v; e[cnt].nex=ep[u]; ep[u]=cnt; } void addq(int u,int v) { ++tot; q[tot].to=v; q[tot].nex=qp[u]; qp[u]=tot; } void dfs(int u) { vis[u]=1;fa[u]=u; for(int i=ep[u];i;i=e[i].nex) { int v=e[i].to; if(!vis[v]){dfs(v);fa[v]=u;} } for(int i=qp[u];i;i=q[i].nex) { int v=q[i].to; if(vis[v]) { q[i].ans=found(v); if(i&1)q[i+1].ans=q[i].ans; else q[i-1].ans=q[i].ans; } } } int main() { n=read(),m=read(),s=read(); for(int i=1;i<n;++i) { int x=read(),y=read(); adde(x,y);adde(y,x); } for(int i=1;i<=m;++i) { int x=read(),y=read(); addq(x,y);addq(y,x); } dfs(s); for(int i=1;i<=m;++i) printf("%d\n",q[i<<1].ans); return 0; }
Tarjan LCA(wypx)

偷著放一份s菌的代碼

技術分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<algorithm>
using namespace std;
int read(){
    int an=0,f=1;char ch=getchar();
    while(!(0<=ch&&ch<=9)){if(ch==-)f=-f;ch=getchar();}
    while(0<=ch&&ch<=9){an=an*10+ch-0;ch=getchar();}
    return an*f;
}
int n,m,s,cnt,qf[500099],f[500099],fa[500099],ans[500099<<1];
int x,y;
bool vis[500099];
int found(int x){
    if(fa[x]!=x)fa[x]=found(fa[x]);
    return fa[x];}
struct saber{
int to,nex;
}b[500099<<1];
struct question{
int to,nex;
}qu[500099<<1];
void add(int x,int y){
    cnt++;b[cnt].to=y;
    b[cnt].nex=f[x];f[x]=cnt;
}
void add(int x,int y,int z){
    qu[z].to=y;
    qu[z].nex=qf[x];
    qf[x]=z;
}
void dfs(int x){
    fa[x]=x;vis[x]=1;//cout<<x<<" ";
    for(int i=f[x];i;i=b[i].nex){
        int v=b[i].to;
        if(!vis[v]){
            dfs(v);
            fa[v]=x;
        }
    }
    for(int i=qf[x];i;i=qu[i].nex){
        int v=qu[i].to;
        if(vis[v]){
            ans[i]=found(v);
            if(i&1)ans[i+1]=ans[i];
            else ans[i-1]=ans[i];
        }
    }
}
int main(){
    n=read();m=read();s=read();
    for(int i=1;i<n;i++){
        int x,y;x=read();y=read();
        add(x,y);add(y,x);
    }
    for(int i=1;i<=m;i++){
        x=read();y=read();
        add(x,y,i*2-1);add(y,x,i*2);
    }
    dfs(s);
    for(int i=1;i<=m;i++){
        cout<<ans[2*i]<<endl;}
    return 0;
}
Tarjan LCA (s_a_b_e_r)

by:wypx

Tarjan之求LCA