zoukankan      html  css  js  c++  java
  • [模板] LCA

    离线tarjan(dfs)
    链式前向星从1开始存,免了赋-1初值,方便异或运算,好处多多。
    并查集fa数组的初始化可以写入dfs中顺便执行,少一个大循环。

    数组要开大,不然会报WA,可能它在乱搜吧。

    //Writer:GhostCai && His Yellow Duck
    
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    
    const int MAXN=2000000;
    
    int m,n,root;
    
    inline int read_d(){
        int i=0;
        char c;
        while(c=getchar(),c<'0'||c>'9');
        while(c<='9'&&c>='0'){
            i=i*10+c-'0';
            c=getchar();
        }
        return i;
    }
    
    int fa[MAXN];
    int fnd(int x){
        return fa[x]==x?x:fa[x]=fnd(fa[x]);
    }
    inline void cat(int x,int y){
        x=fnd(x);y=fnd(y);
        fa[y]=x;
    }
    
    struct Ques{
        int next,id,lca;
    }qs[MAXN];
    int qhead[MAXN],qcnt=1;
    inline void qadd(int x,int y){
        qs[++qcnt].id = y;
        qs[qcnt].next = qhead[x];
        qhead[x]=qcnt;
    }
    
    
    struct Edge{
        int next,to;
    }e[MAXN];
    int head[MAXN],ecnt=1;
    inline void add(int x,int y){
        e[++ecnt].next = head[x];
        e[ecnt].to = y;
        head[x]=ecnt;
    }
    
    bool vis[MAXN];
    int dfs(int id){
        vis[fa[id]=id]=1;
    //  fa[id]=id;
        for(int i=head[id];i;i=e[i].next){
            int v=e[i].to ;
            if(vis[v]) continue;
            dfs(v);
            cat(id,v);
        }
        for(int i=qhead[id];i;i=qs[i].next){
            int v=qs[i].id ;
            if(!vis[v]) continue;
            qs[i^1].lca = qs[i].lca = fnd(v);
    //      if(i%2) qs[i+1].lca = qs[i].lca ;
    //      else qs[i-1].lca = qs[i].lca ;
        }
    }
    
    int main(){
        int  x,y;
    //  cin>>n>>m>>root;
        scanf("%d%d%d",&n,&m,&root);
    //  for(int i=1;i<=n;i++) fa[i]=i;
    //  memset(head,-1,sizeof(head));
    //  memset(qhead,-1,sizeof(qhead));
        for(int i=1;i<=n-1;i++){
    //      cin>>x>>y;
    //      x=read_d();
    //      y=read_d();
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        for(int i=1;i<=m;i++){
    //      cin>>x>>y;
    //      x=read_d();
    //      y=read_d();
            scanf("%d%d",&x,&y);
            qadd(x,y);
            qadd(y,x);
        }
        dfs(root);
        for(int i=1;i<=m;i++){
            printf("%d
    ",qs[i<<1].lca);
        }
    }
    

    在线 倍增求法
    洛谷模板题cin会T,偷懒写builtin

    //Writer:GhostCai && His Yellow Duck
    
    #include<iostream>
    #include<cmath>
    using namespace std;
    
    const int MAXN=1000000;
    
    int n,m,root;
    int dep[MAXN],f[MAXN][32];
    int len;
    
    struct Edge{
        int next,to;
    }e[MAXN];
    int head[MAXN],ecnt=1;
    inline void add(int x,int y){
        e[++ecnt].to = y;
        e[ecnt].next = head[x];
        head[x] = ecnt;
    } 
    
    void dfs(int now,int pre){
        dep[now]=dep[pre]+1;
        f[now][0]=pre;
        for(int i=head[now];i;i=e[i].next){
            int v=e[i].to ;
            if(v==pre) continue;
            dfs(v,now);
        }
    }
    
    void redouble(){
        for(int j=1;(1<<j)<=n;j++){
            for(int i=1;i<=n;i++){
                if(dep[i]-(1<<j)<0) continue;
                f[i][j]=f[f[i][j-1]][j-1];
            }
        }
    
    } 
    
    int query(int x,int y){
        if(dep[x]<dep[y]) swap(x,y);
    //  for(int i=len;i>=0;i--){
    //      if(dep[x]-(1<<i)<dep[y]) continue;
    //      x=f[x][i];//
    //  }
    //  ======================================
    //  int d=dep[x]-dep[y];
    //  while(d){
    //      x=f[x][(int)log2(d&(-d))];
    //      d-=d&(-d);
    //  }
    //  ======================================
        int d=dep[x]-dep[y],k=0;
        while(d){
            if(d&1) x=f[x][k];
            k++;
            d>>=1;
        }
        if(x==y) return x;///////
        for(int i=len;i>=0;i--){
            if(f[x][i]==f[y][i]) continue;
            x=f[x][i]; y=f[y][i];
        }
        return f[x][0];
    }
    
    
    int main(){
        cin.sync_with_stdio(false);
        cin.tie(0);
        cin>>n>>m>>root;
        len=log(n)/log(2);
        for(int i=1;i<=n-1;i++){
            int x,y;
            cin>>x>>y;
            add(x,y);
            add(y,x);
        }
        dfs(root,0);
        redouble();
        for(int i=1;i<=m;i++){
            int x,y;
            cin>>x>>y;
            cout<<query(x,y)<<endl;
        }
        return 0;
    }
    

    树剖,极其好写,还是在线查询,常数小,速度媲美tarjan。

    #include<iostream>
    #include<cstdio>
    
    using namespace std;
    
    const int MAXN=500005;
    
    int n,m,st;
    
    inline int rd(){
      int ret=0,f=1;char c;
      while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
      while(isdigit(c))ret=ret*10+c-'0',c=getchar();
      return ret*f;
    }
    
    struct Edge{
      int next,to,w;
    }e[MAXN<<1];
    int ecnt,head[MAXN];
    inline void add(int x,int y,int w){
      e[++ecnt].to = y;
      e[ecnt].w = w;
      e[ecnt].next = head[x];
      head[x] = ecnt;
    }
    
    int fa[MAXN],dep[MAXN],siz[MAXN],hch[MAXN];
    void dfs1(int cur,int pre){
      fa[cur]=pre;dep[cur]=dep[pre]+1;siz[cur]=1;
      int mx=-1;
      for(int i=head[cur];i;i=e[i].next){
        int v=e[i].to;
        if(v==pre) continue;
        dfs1(v,cur);
        siz[cur]+=siz[v];
        if(siz[v]>mx) hch[cur]=v,mx=siz[v];
      }
    }
    int id[MAXN],top[MAXN],cnt;
    void dfs2(int cur,int tp){
      id[cur]=++cnt;top[cur]=tp;
      if(hch[cur]) dfs2(hch[cur],tp);
      for(int i=head[cur];i;i=e[i].next){
        int v=e[i].to;
        if(v==fa[cur]||v==hch[cur]) continue;//
        dfs2(v,v);
      }
    }
    
    int lca(int x,int y){
      while(top[x]!=top[y]){
        dep[top[x]]>=dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
      }
      return dep[x]<=dep[y]?x:y;
    }
    
    int main(){
      n=rd();m=rd();st=rd();
      int x,y;
      for(int i=1;i<=n-1;i++){
        x=rd();y=rd();
        add(x,y,1);add(y,x,1);
      }
      dfs1(st,0);
      dfs2(st,st);
      for(int i=1;i<=m;i++){
        x=rd();y=rd();
        printf("%d
    ",lca(x,y));
      }
      return 0;
    }

    本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9247491.html

  • 相关阅读:
    三数之和
    盛最多水的容器
    正则表达式匹配
    最长回文子串
    寻找两个有序数组的中位数
    2、二维数组中的查找
    1、找出数组中重复的数字
    mongodb的下载地址
    提取快捷方式的图标资源问题
    一条数据引发的问题
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9247491.html
Copyright © 2011-2022 走看看