zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",xz,ans);
            }else{
                ans=dep[x]+dep[y]+dep[z]-dep[xy]-dep[xy]-dep[xz]+dep[xy]-dep[xz];
                printf("%d %d
    ",xy,ans);
            }
    
        }
    
    
    }
    

    树剖求LCA

    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f
    #define DOF 0x7f7f7f7f
    #define endl '
    '
    #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;
        }
    
    
    }
    
  • 相关阅读:
    Java 数量为5的线程池同时运行5个窗口买票,每隔一秒钟卖一张票
    Android Notification
    Android DatePickerDialog TimePickerDialog
    Android Toast 提示按两次返回键退出
    Android Toast 自定义
    Android ProgressDialog 加载进度
    Android 自定义Dialog
    Android Dialog AlertDialog
    Android BaseAdapter ListView (明星简介列表)
    Android SimpleAdapter ListView (锁定手机,解锁手机的列表)
  • 原文地址:https://www.cnblogs.com/waryan/p/13471997.html
Copyright © 2011-2022 走看看