LCA(最近公共祖先)

LCA

\(LCA\)=最近公共祖先。

1.初始化\(lg\)数组,其代表\(lg2+1\)

2.利用倍增的思想去求\(fa[u][i]\),在\(u\)点向上走\(2^i\)步时的祖先是谁。深度\(dep\)也同时求出。

3.初始化\(fa[u][0]=father\)

4.\(LCA\)

int LCA(int x,int y){
    if(dep[x]<dep[y])
        swap(x,y);
    while(dep[x]>dep[y]){
        x=fa[x][lg[dep[x]-dep[y]]-1];//一直跳直到深度相同
    }
    if(x==y)return x;
    for(int k=lg[dep[x]]-1;k>=0;--k){
        if(fa[x][k]!=fa[y][k])//向上跳从大->小,第一个不相等的点就是公共祖先的儿子
            x=fa[x][k],y=fa[y][k];
    }

    return fa[x][0];

P3379 【模板】最近公共祖先(LCA)

#include<bits/stdc++.h>
using namespace std;
//#define int long long
int n,m,s;
const int maxn=5e5+10;
int head[maxn],tot=0;

struct edge{
    int to,next;
}edge[maxn<<1];

void add(int u,int v){
    edge[++tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot;
}
int dep[maxn],fa[maxn][22],lg[maxn];


void dfs(int u,int father){
    dep[u]=dep[father]+1;
    fa[u][0]=father;
    for(int i=1;i<=lg[dep[u]];++i){
        fa[u][i]=fa[fa[u][i-1]][i-1];
    }
    for(int i=head[u];i;i=edge[i].next){
        int v=edge[i].to;
        if(v==father)continue;
        dfs(v,u);
    }

}

int LCA(int x,int y){
    if(dep[x]<dep[y])
        swap(x,y);
    while(dep[x]>dep[y]){
        x=fa[x][lg[dep[x]-dep[y]]-1];
    }
    if(x==y)return x;
    for(int k=lg[dep[x]]-1;k>=0;--k){
        if(fa[x][k]!=fa[y][k])
            x=fa[x][k],y=fa[y][k];
    }

    return fa[x][0];
}

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>m>>s;
    for(int i=1;i<n;++i){
        int x,y;cin>>x>>y;
        add(x,y);add(y,x);
    }
    for(int i=1;i<maxn;++i){
        lg[i]=lg[i-1]+(1<<lg[i-1]==i);
    }
    dfs(s,0);
    for(int i=1;i<=m;++i){
        int a,b;cin>>a>>b;
        cout<<LCA(a,b)<<endl;
    }


}

P4281[AHOI2008]紧急集合、聚会

思路

求三个点的\(lca\)\(xy,xz,yz\)。我们容易知道的是必有两个\(lca\)是相等的(画图易得),然后我们选择不相等的那个\(lca\)作为最终的终点可。(画图易得)

倍增求LCA

#include<bits/stdc++.h>
using namespace std;
//#define int long long
int n,m,s;
const int maxn=5e5+10;
int head[maxn],tot=0;

struct edge{
    int to,next;
}edge[maxn<<1];

void add(int u,int v){
    edge[++tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot;
}
int dep[maxn],fa[maxn][22],lg[maxn];


void dfs(int u,int father){
    dep[u]=dep[father]+1;
    fa[u][0]=father;
    for(int i=1;i<=lg[dep[u]];++i){
        fa[u][i]=fa[fa[u][i-1]][i-1];
    }
    for(int i=head[u];i;i=edge[i].next){
        int v=edge[i].to;
        if(v==father)continue;
        dfs(v,u);
    }

}

int LCA(int x,int y){
    if(dep[x]<dep[y])
        swap(x,y);
    while(dep[x]>dep[y]){
        x=fa[x][lg[dep[x]-dep[y]]-1];
    }
    if(x==y)return x;
    for(int k=lg[dep[x]]-1;k>=0;--k){
        if(fa[x][k]!=fa[y][k])
            x=fa[x][k],y=fa[y][k];
    }

    return fa[x][0];
}

signed main(){
//    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//cin>>n>>m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;++i){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    for(int i=1;i<maxn;++i){
        lg[i]=lg[i-1]+(1<<lg[i-1]==i);
    }
    dfs(1,0);
    for(int i=1;i<=m;++i){
        int x,y,z;
//        cin>>x>>y>>z;
        scanf("%d%d%d",&x,&y,&z);
        int xy=LCA(x,y),xz=LCA(x,z),yz=LCA(y,z);
        int ans;
        if(xy==xz){
            ans=dep[x]+dep[y]+dep[z]-dep[yz]-dep[yz]-dep[xz]+dep[yz]-dep[xz];
            printf("%d %d\n",yz,ans);
//            cout<<yz<<" "<<ans<<endl;
        }else if(xy==yz){
            ans=dep[x]+dep[y]+dep[z]-dep[xz]-dep[xz]-dep[xy]+dep[xz]-dep[yz];
            printf("%d %d\n",xz,ans);
        }else{
            ans=dep[x]+dep[y]+dep[z]-dep[xy]-dep[xy]-dep[xz]+dep[xy]-dep[xz];
            printf("%d %d\n",xy,ans);
        }

    }


}

树剖求LCA

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define DOF 0x7f7f7f7f
#define endl '\n'
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(case, x) cout << case << "  : " << x << endl
#define open freopen("ii.txt", "r", stdin)
#define close freopen("oo.txt", "w", stdout)
#define IO                       \
    ios::sync_with_stdio(false); \
    cin.tie(0);                  \
    cout.tie(0)
#define pb push_back
using namespace std;
//#define int long long
#define lson rt << 1
#define rson rt << 1 | 1
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<long long, long long> PII;
const int maxn = 5e5 + 10;

int n, m, s;

int head[maxn], tot;
struct edge {
    int to, next;
} edge[maxn<<1];

int w[maxn], wt[maxn];
//w输入时的权值,wt编号后的权值

int son[maxn], id[maxn], fa[maxn], dep[maxn], sz[maxn], top[maxn], cnt = 0;
//son重儿子、id新编号、fa父亲节点、dep深度、sz子树大小、top顶端、cnt标号。
void add(int u, int v) {
    edge[++tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot;
}

void dfs1(int u, int father) {
    dep[u] = dep[father] + 1;
    sz[u] = 1;
    fa[u] = father;
    int maxson = -1;
    for(int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].to;
        if(v == father)continue;
        dfs1(v, u);
        sz[u] += sz[v];
        if(sz[v] > maxson)
            son[u] = v, maxson = sz[v];
    }

}

void dfs2(int u, int topf) {
    id[u] = ++cnt;
    wt[cnt] = w[u];
    top[u] = topf;
    if(!son[u]) return ;
    dfs2(son[u], topf);
    for(int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].to;
        if(v == fa[u] || v == son[u]) continue;
        dfs2(v, v);
    }

}

int LCA(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        x=fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m >> s;
    for(int i = 1; i < n; ++i) {
        int x, y;
        cin >> x >> y;
        add(x, y);
        add(y, x);
    }
    dfs1(s,0);
    dfs2(s, s);
    for(int i = 1; i <= m; ++i) {
        int a, b;
        cin >> a >> b;
        cout << LCA(a, b) << endl;
    }


}
posted @ 2020-08-10 20:29  waryan  阅读(185)  评论(0编辑  收藏  举报