精华内容
下载资源
问答
  • 倍增LCA

    2019-11-08 15:17:23
    倍增LCA #define maxn 100005 using namespace std; int n,m,s,t; int dep[maxn],head[maxn],f[maxn][20]; struct node { int to; int next; }e[maxn]; inline void add(int u,int v) { ++t;...

    倍增LCA

    #include<bits/stdc++.h>
    #define maxn 100005
    
    using namespace std;
    
    int n,m,s,t;
    int dep[maxn],head[maxn],f[maxn][20];
    
    struct node
    {
    	int to;
    	int next;
    }e[maxn];
    
    inline void add(int u,int v)
    {
    	++t;
    	e[t].to = v;
    	e[t].next = head[u];
    	head[u] = t;
    }
    
    inline int lca(int x,int y)
    {
        if(dep[x]<dep[y]) swap(x,y);
    	for(int i=20;i>=0;i--)
    	{
    	    if(dep[f[x][i]]>=dep[y]) x = f[x][i];
    		if(x==y) return x;
    	}
    	for(int i=20;i>=0;i--)
    	{
    		if(f[x][i]!=f[y][i])
    		{
    			x = f[x][i];
    			y = f[y][i];
    		}
    	}
    	return f[x][0];
    }
    
    inline void dfs(int u,int fa)
    {
    	dep[u] = dep[fa]+1;
    	for(int i=1;(1<<i)<=dep[u];i++)
    	{
    	    f[u][i] = f[f[u][i-1]][i-1];
    	}
    	for(int i=head[u];i>0;i=e[i].next)
    	{
    		int v = e[i].to;
    		if(v==fa) continue;
    		f[v][0] = u;
    		dfs(v,u);
    	}
    }
    
    int main()
    {
        cin>>n>>m>>s;
    	for(int i=1;i<n;i++)
    	{
    	    int u,v;
    		cin>>u>>v;
    		add(u,v);
    	}
    	dfs(s,0);
    	for(int i=1;i<=m;i++)
    	{
    	    int x,y;
    		cin>>x>>y;
    		cout<<lca(x,y)<<endl;
    	}
    	return 0;
    }
    
    展开全文
  • 倍增lca

    2019-11-15 14:44:46
    倍增lca ```cpp #include<bits/stdc++.h> using namespace std; const int M=5e5+100; struct st{ int nxt,to; }edge[M<<1]; int head[M],num; void add(int x,int y){ edge[++num].to=y; edge[num]...

    倍增lca

    
    ```cpp
    #include<bits/stdc++.h>
    using namespace std;
    const int M=5e5+100;
    struct st{
    	int nxt,to;
    }edge[M<<1];
    int head[M],num;
    void add(int x,int y){
    	edge[++num].to=y;
    	edge[num].nxt=head[x];
    	head[x]=num;
    }
    int n,m,s,f[20][M],dep[M];
    //f[i][x]表示x的上面2^i层是多少 
    void dfs(int u,int father){
    	dep[u]=dep[father]+1;//深度 
    	f[0][u]=father;
    	for(int i=1;i<=18;i++)//从小到大 
    	f[i][u]=f[i-1][f[i-1][u]];//递推,u的上方2^(i-1)层的再上面2^(i-1)层是2^i层 
    	for(int i=head[u];i;i=edge[i].nxt){
    		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);//保证y在下面 
    	for(int i=18;i>=0;i--){
    	   if(dep[f[i][y]]>=dep[x])y=f[i][y];//向上跳在x下面 
    	   if(x==y)return x;
    	}
    	for(int i=18;i>=0;i--)
    	if(f[i][x]!=f[i][y]){
    			x=f[i][x];
    			y=f[i][y];
    	}//不一样就向上跳,实际是二进制的想法 
    	return f[0][x];//最后肯定在下一层 
    }
    int main(){
    	scanf("%d%d%d",&n,&m,&s);
    	for(int i=1,u,v;i<n;i++){
    		scanf("%d%d",&u,&v);
    		add(u,v);
    		add(v,u);
    	}
    	dfs(s,0);
    	while(m--){
    		int a,b;
    		scanf("%d%d",&a,&b);
    		printf("%d\n",lca(a,b));
    	}
    	return 0;
    }
    
    
    
    展开全文
  • 倍增 LCA

    2019-10-04 23:58:35
    以NOIP2013提高组day1 最后一道题为例来学的倍增lca。其实这套题早就做过了,倍增lca也学过,只不过当时没有理解清楚,所以今天再次学了一遍,虽然没有时间编程序了,但是先把思路和做法在这里梳理一遍,下次来...

      以NOIP2013提高组day1 最后一道题为例来学的倍增和lca。其实这套题早就做过了,倍增和lca也学过,只不过当时没有理解清楚,所以今天再次学了一遍,虽然没有时间编程序了,但是先把思路和做法在这里梳理一遍,下次来编。

      首先,倍增。(树上倍增)

      f[i][j]表示在 j 节点向上跳2^ i 步后的节点。由2^ i =2^( i-1)+2^(i-1)可以得到递推式:f[i][j]=f[i-1][f[i-1][j]]。解释:从j节点向上跳2^ i 就相当于从j节点向上先跳2^(i-1)步到得节点,再从这个节点向上跳2^(i-1)步所到的点。

      所以得到:

    1 void bz()//倍增 
    2 {
    3     for(int i=1;i<=14;i++)//i根据题意(深度)调大小
    4         for(int j=1;j<=n;j++)
    5             fa[i][j]=fa[i-1][fa[i-1][j]];       
    6 }

      然后就是找lca(最近公共祖先)

      在这之前,首先要明确这两个点在树上的深度,先将较深的点向上跳到与另一点一样高(需要两点的深度差dh),然后再一起向上跳到最近公共祖先。怎么才能使两个点在同一深度呢?有两种方法,这里讲二进制的方法。深度差可以表示为二进制形式,如当dh=5时,为101,即这个点要在为1 的地方跳,先跳2^0步到一个节点,再从这个节点向上跳2^2步。可以用 if (1<< i & dh) 判断,当不等于0时,说明dh在第 i 位为1 ,需要跳,等于0时不需要跳就不管,每次更新跳到位置。

    for(int i=0;i<=14;i++)//使两个点深度相同 
        {
            if(1<<i&dh)//位运算 
            {
               // t1=min(t1,minax[i][s]);
                s=fa[i][s]; 
            }
        } 

      然后就是两个点一起向上跳到公共祖先,只需判断他们跳到的点是不是相同就可以了,因为如果超出了最近公共祖先那么他们跳到的节点就一定是同一节点,这时i 不可取,将 i 倒序循环,这样如果超过lca就会跳较少的步数到下面一点来判断是不是lca,如果这个时候又跳得太小了,那么更新现在跳到的节点,i 继续减小,从这个节点继续向上跳,重复上面的判断,由于跳的步数越来越少,越来越接近lca,那么最后一次一定是最接近lca的,这时,一定是跳两步多了,跳一步少了,所以刚好在lca下一个节点处,再加上1 即可。

     1 int lca(int s,int v)//找最近公共祖先,并求出最小值
     2 {
     3     int t1=INF,t2=INF;//两边子树最小值
     4     if(F(s)!=F(v))return -1;//判断是否连通 
     5     if(depth[v]>depth[s])//保证s在v下面
     6         swap(s,v);
     7     int dh=depth[s]-depth[v];
     8     for(int i=0;i<=14;i++)//使两个点深度相同 
     9     {
    10         if(1<<i&dh)//位运算 
    11         {
    12             t1=min(t1,minax[i][s]);
    13             s=fa[i][s]; 
    14         }
    15 
    16     } 
    17     if (s==v) return t1; //判断是否已经满足 
    18     for(int i=14;i>=0;i--)
    19     {
    20         if(fa[i][s]!=fa[i][v])
    21         {
    22             t1=min(t1,minax[i][s]);
    23             t2=min(t2,minax[i][v]);
    24             s=fa[i][s];
    25             v=fa[i][v];
    26         }
    27     }
    28     //此时两点都在最近公共祖先的下面,只需再向上走一步 
    29     t1=min(t1,minax[0][s]);
    30     t2=min(t2,minax[0][v]);
    31     return min(t1,t2);
    32 }

      下来自己写一遍。。。谢谢anantheparty的博客。

       2016 10 09

      今天把货车运输这道题A了。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<queue>
      6 #define maxn 10005
      7 #define inf 100005
      8 #define INF 12345678
      9 using namespace std;
     10 int n,m,q,fat[maxn],deth[maxn];
     11 int tot,he[maxn],ne[inf],to[inf],w[inf];
     12 int mimax[16][maxn],f[16][maxn];
     13 bool notin[inf],flag[maxn];//notin[inf] not notin[maxn]  RE
     14 struct pp{
     15     int x,y,v;
     16 };
     17 pp road[inf];
     18 const int comp(const pp&a,const pp&b )
     19 {
     20     return a.v>b.v;
     21 }
     22 void add(int a,int b,int c)
     23 {
     24     tot++;to[tot]=b;ne[tot]=he[a];w[tot]=c;he[a]=tot;
     25 }
     26 int find(int a)
     27 {
     28     if (fat[a]!=a) return fat[a]=find(fat[a]);
     29     return fat[a];
     30 }
     31 void kruskal()
     32 {
     33     for (int i=1;i<=n;i++)
     34       fat[i]=i;
     35     for (int i=1;i<=2*m;i++)
     36     {
     37         int r1=find(road[i].x),r2=find(road[i].y);
     38         if (r1!=r2) fat[r2]=r1;
     39         else notin[i]=true;
     40     }
     41 }
     42 void dfs(int u)
     43 {
     44     for (int i=he[u];i;i=ne[i])
     45       if (!flag[to[i]]){
     46           flag[to[i]]=1;
     47           deth[to[i]]=deth[u]+1;
     48           f[0][to[i]]=u;
     49           mimax[0][to[i]]=w[i];//mimax[0][to[i]]
     50           dfs(to[i]);
     51         }
     52 }
     53 void bz()
     54 {
     55     for (int i=1;i<=14;i++)// i=1!!!
     56       for (int j=1;j<=n;j++)
     57       {
     58           f[i][j]=f[i-1][f[i-1][j]];
     59           mimax[i][j]=min(mimax[i-1][j],mimax[i-1][f[i-1][j]]);//mimax[i-1][j],f[i-1][j]
     60       }
     61 }
     62 int lca(int a,int b)
     63 {
     64     int r1=INF,r2=INF;
     65     if (find(a)!=find(b)) return -1;
     66     if (deth[a]<deth[b]) swap(a,b);
     67     int d=deth[a]-deth[b];
     68     for (int i=0;i<=14;i++)
     69     {
     70         if (1<<i & d)
     71         {
     72             r1=min(mimax[i][a],r1);
     73             a=f[i][a];
     74         }
     75     }
     76     if (a==b) return r1;
     77     for (int i=14;i>=0;i--)
     78     {
     79         if (f[i][a]!=f[i][b])
     80         {
     81             r1=min(mimax[i][a],r1);
     82             r2=min(mimax[i][b],r2);
     83             a=f[i][a];
     84             b=f[i][b];
     85         }
     86     }
     87     r1=min(r1,mimax[0][a]);//!
     88     r2=min(r2,mimax[0][b]);//! 还有一步 
     89     return min(r1,r2);
     90 }
     91 int main()
     92 {
     93 //    freopen("truck_lca.in","r",stdin);
     94     cin>>n>>m;
     95     for (int i=1;i<=m;i++)
     96     {
     97         int a,b,c;
     98         scanf("%d%d%d",&a,&b,&c);
     99         road[i*2-1].x=a;road[i*2].x=b;
    100         road[i*2-1].y=b;road[i*2].y=a;
    101         road[i*2-1].v=c;road[i*2].v=c;
    102     }
    103     sort(road+1,road+1+2*m,comp);
    104     kruskal();
    105     for (int i=1;i<=2*m;i++)
    106       if (!notin[i]) {
    107           add(road[i].x,road[i].y,road[i].v);
    108           add(road[i].y,road[i].x,road[i].v);
    109       }
    110     for (int i=1;i<=n;i++)
    111      if (!deth[i]){
    112          int r=find(i);
    113          deth[r]=1;
    114          flag[r]=1;
    115          dfs(r);
    116      }
    117      bz();
    118      cin>>q;
    119      for (int i=1;i<=q;i++)
    120      {
    121          int a,b;
    122          scanf("%d%d",&a,&b);
    123          printf("%d\n",lca(a,b));
    124      }
    125      return 0;
    126 }

      还是有很多小细节需要注意啊。。。

    转载于:https://www.cnblogs.com/lx0319/p/5940253.html

    展开全文
  • 倍增 lca

    2017-05-05 15:09:00
    询问 x,y的 lca 设y更深 "假设有一个 dad[][] 数组 dad[x][j] 表示 x 的 2^j 级 祖先 例如 dad[x][0] 是 x 的 baba dad[x][1] 是 x 的 yeye (baba 的 baba) dad[x][2] 是 x 的 yeye 的 yeye ...

    GeneralLiu

     

    近似二分思想

     

    询问 x,y的 lca

    设y更深

    "假设有一个 dad[][] 数组

     dad[x][j] 表示 x 的 2^j 级 祖先

     例如 dad[x][0] 是 x 的 baba

            dad[x][1] 是 x 的 yeye (baba 的 baba)

            dad[x][2] 是 x 的 yeye 的 yeye

     所以递推式 dad[x][j+1] = dad[  dad[x][j]  ][ j ](套上 上两行就理解了)"

    其实 有了递推式 dad[][]数组 就可求了

     

     

     

    1    将 y 跳到与 x 深度一样的 那一层

      如果 x == y 则返回 x 或 y

      (这是 x 与 y 在一条链上的情况

        如 LCA(4,2)=2

         4 上升到 与 2 同层

         发现 与 2 重合

         则 返回 2)

     

    2  两点 同时 倍增

      若 满足 x ,y 的 2^j 级祖先不同(此祖先 在 lca祖先 下方)

      则 同时 上跳 2^j 级

      最后 返回 x (或 y)的 父亲

      (这是 x 与 y 不在一条链上的情况

        如 LCA(8 ,6)=1

         8 上升到 与 6 同层

      `   8-->7

         发现 不与 6 重合

         则

         若上升 2 层(2^1)

          由于 7 与 6 的 2 级 祖先 均为 1

           于是 尝试 上升 1 层(2^0)

          由于 7 与 6 的 1 级 祖先 不同

          所以 7-->2 , 6-->5

         倍增结束

          因为 最后一个是 2^0 级祖先 , (-1)就不合法了

         返回 2(或5)的 父亲 1

        即 lca(8,6))

     

    # include <iostream>
    # include <cstdio>
    # include <cstring>
    # include <string>
    # include <cmath>
    # include <vector>
    # include <map>
    # include <queue>
    # include <cstdlib>
    # define MAXN 500001
    using namespace std;
    
    int n, m, s;
    int f[MAXN][25], deep[MAXN];//f[i][j] 为 i 的 2^j 级祖先 
    vector <int> vec[MAXN];
    
    int get_num() {
        int k = 0, f = 1;
        char c = getchar();
        for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for(; isdigit(c); c = getchar()) k = k * 10 + c - '0';
        return k * f;
    }
    
    void dfs(int u)//预处理 深度, f数组 
    {
        int i, v;
        deep[u] = deep[f[u][0]] + 1;
        for(i = 0; f[u][i]; i++) f[u][i + 1] = f[f[u][i]][i];
        for(i = 0; i < vec[u].size(); i++)
        {
            v = vec[u][i];
            if(!deep[v]) f[v][0] = u, dfs(v);
        }
    }
    
    int lca(int x, int y)//倍增 求 lca 
    {
        int i;
        if(deep[x] < deep[y]) swap(x, y);
        for(i = 20; i >= 0; i--)
            if(deep[f[x][i]] >= deep[y])
                x = f[x][i];
        if(x == y) return x;
        for(i = 20; i >= 0; i--)
            if(f[x][i] != f[y][i])
                x = f[x][i], y = f[y][i];
        return f[x][0];
    }
    
    int main()
    {
        int i, x, y;
        n = get_num();
        m = get_num();
        s = get_num();
        for(i = 1; i < n; i++)
        {
            x = get_num();
            y = get_num();
            vec[x].push_back(y);
            vec[y].push_back(x);
        }
        dfs(s);
        for(i = 1; i <= m; i++)
        {
            scanf("%d %d", &x, &y);
            printf("%d\n", lca(x, y));
        }
        return 0;
    }

     

    转载于:https://www.cnblogs.com/1227xq/p/6784474.html

    展开全文
  • 约会 倍增lca

    2019-10-03 12:33:58
    题意:一棵树,给两个点,求树上有...倍增lca,分好多情况讨论。。 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #define N 1005...
  • 倍增LCA专题

    2019-10-07 07:14:30
    说到倍增LCA,我不得不想起的就是NOIP2013货车运输。这题的原题其实是UVA11354。当年向SKYDEC学习了一下写法,但是不求甚解,只知道做法却不太明白所以然。后来也碰到过好几次类似的。最近想做个总结,首先重写了一...
  • 树上倍增LCA

    2020-08-21 13:44:59
    树上倍增LCA LCA:最近公共祖先 朴素思想求LCA,有x,y两点,x、y有不同的深度,depth[x]、depth[y]。首先取x,y的深度最大的点一步一步往上追溯直到x与y的深度相同,再x与y共同追溯直到发现到相同的一点,这一点...
  • 倍增LCA模板

    2017-07-29 19:20:11
    poj 1330即一道倍增LCA模板题,注意在倍增往上跳时每个while语句的终止条件,WA了后几次就是因为跳飞了。。。#include #include #include #include #include using namespace std; const int maxn=10004; int n;
  • 倍增LCA笔记

    2016-09-28 22:02:32
    学习倍增LCA很久了……却一直没有写一篇学习笔记(其实我也不太写这种东西) 对于在线LCA算法,我们先思考最暴力的方法:直接往上推,写出两个结点的祖先,然后找到最早的一个。 显而易见会T飞辣。 考虑优化一下...
  • 倍增LCA复习

    2016-09-20 16:29:11
    时间过去了如此之久,我连倍增LCA都不怎么记得了,要粗事啊。 首先预处理层数和每个节点的父亲,然后预处理p数组,p[i,j]表示i向上第2^j个祖先。最后对于每个询问x,y先把x,y变成同一层数的(x或y向上走直到两个层数...
  • 图论:倍增LCA模板

    2020-07-26 22:05:12
    倍增LCA */ #include <bits/stdc++.h> using namespace std; const int maxn=5e5+10; int fa[maxn][30]; int n,m,s; int head[maxn],cnt=0; int dep[maxn]; struct node{ int v,next; }e[maxn<<1]; ...
  • 最后利用倍增Lca,在算Lca的过程中,顺便计算沿途最小值 说明:   最大生成树,只保留了权值最大的那些边,而且每个点互相之间都可以到达,不用经过那些权值较小的边 注意: Lca倍增时,要先算最小值,再倍增 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,113
精华内容 1,245
关键字:

倍增lca