• LCA(树上倍增 || rmq&lca||)


     

    背景&&描述

        给出一棵根节点为1的树,每次询问两点之间的最近公共祖先。

    输入格式

        第一行一个整数n表示树的节点个数

        第二行n-1个数,第i个数表示点(i+1)的父亲是哪个点。保证第i个数<=i。

        第三行一个整数m表示询问个数。

        接下来m行,每行有俩整数,表示询问的俩点。

    输出格式

        共m行,对于每次询问输出最近公共祖先的编号。

    样例输入

    6
    1 2 1 2 4
    3
    3 5
    6 4
    2 6
    

    样例输出

    2
    4
    1

    数据范围与约定

    对于100%的数据:1leq n,m leq 2*10^5

    ===================

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    const int N=200050;
    struct node
    {
        int to,next;
    }e[N];
    int first[N],dep[N],visit[N];
    int fa[N][30];
    int cnt=0;
    void insert(int u,int v)
    {
        e[++cnt].to=v;e[cnt].next=first[u];first[u]=cnt;
        e[++cnt].to=u;e[cnt].next=first[v];first[v]=cnt;
    }
    void dfs(int x)
    {
        visit[x]=1;
        for(int i=1;(1<<i)<=dep[x];i++)
            fa[x][i]=fa[fa[x][i-1]][i-1];
        for(int k=first[x];k;k=e[k].next)    
        if(!visit[e[k].to])
        {
            fa[e[k].to][0]=x;
            dep[e[k].to]=dep[x]+1;
            dfs(e[k].to);
        }
    }
    int getlca(int x,int y)
    {
        if(dep[x]<dep[y])    std::swap(x,y);
        int t=dep[x]-dep[y];
        for(int i=0;(1<<i)<=t;i++)
        if((1<<i)&t)    x=fa[x][i];
    
        for(int i=25;i>=0;i--)
        if((1<<i)<=dep[x]&&fa[x][i]!=fa[y][i])
        x=fa[x][i],y=fa[y][i];
        if(x==y)    return x;
        return fa[x][0];
    }
    int main()
    {
        int n;    
        scanf("%d",&n);
        int k;
        for(int i=2;i<=n;i++)        scanf("%d",&k),insert(i,k);
        dfs(1);
        int m;
        scanf("%d",&m);
        int p,q;
        for(int i=1;i<=m;i++)    scanf("%d %d",&p,&q),printf("%d
    ",getlca(p,q));
        return 0;    
    }
    View Code

    LCA树上倍增模版 

    谢谢brain551的教导;

    可以去看他的博客,贼好.

    -------------------------

     这个一道基本上一模一样的题:

    给出一棵以1为根的有n个节点的树。

    m个询问,每次询问ab的最近公共祖先。

    ----------------------

    要LCA树上倍增理解的可以去看看:

    http://www.cnblogs.com/yyf0309/p/5972701.html

    ==============

    lca&rmq(st表)

    自己写了好久,理解不了别人的,只好自己写了一个;

    调了好久只能输出dep;

    用了struct 才A了;

    (12fs 贼菜;)

    区别:f[N<<1][27]是个结构体;(xixi大家应当懂用数组的方法,xixi);

    dp就是dp啊!!zi是第几个(i);

    lca函数 return 的是 zi;

    main 函数 printf 的是 dfn[lca(a,b)];

    要学会st表&&rmq;(xixi)

    调了好久

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using std::swap;
    using std::min;
    const int N=200017;
    inline int read()  
    {  
        int ans=0,f=1;char t=getchar();  
        while(t<'0'||t>'9')   f=(t=='-'?-1:1),t=getchar();  
        while(t>='0'&&t<='9') ans=ans*10+t-'0',t=getchar();  
        return ans*f;  
    }  
    struct edgt
    {
        int depth,zi;
    }line[N];
    int dep[N],tar[N],dfn[N],book[N];
    struct node
    {
        int from,to,next;
    }e[N];
    int first[N];
    int cnt=0;
    void insert(int u,int v)
    {
        e[++cnt].to=v;e[cnt].next=first[u];first[u]=cnt;
        e[++cnt].to=u;e[cnt].next=first[v];first[v]=cnt;
    }
    void dfs(int x)
    {
        dfn[++cnt]=x,tar[x]=cnt,line[cnt].depth=dep[x],line[cnt].zi=cnt;book[x]=1;
        for(int i=first[x];i;i=e[i].next)
        {        
        //    printf("
    **** %d %d
    ",e[i].to,dep[e[i].to]);
            if(!book[e[i].to])
            {            
                dep[e[i].to]=dep[x]+1;
                dfs(e[i].to);            
                line[++cnt].depth=dep[x];
                line[cnt].zi=cnt;    
                dfn[cnt]=x;
            }
        }
    }
    struct flagg
    {
        int dp,zi;
    }f[N<<1][27];
    int lg[N<<1];
    inline int lca(int l,int r)  
    {  
        l=tar[l],r=tar[r];  
        if(l>r)  swap(l,r); 
    //    printf("tar : %d %d
    ",l,r) ;
        int t=lg[r-l+1];  
      //  printf("$ $$ $ : %d %d
    ",f[l][t],f[r-(1<<t)+1][t]);
        int x,y;
        x=f[l][t].dp,y=f[r-(1<<t)+1][t].dp;
        if(x<=y) return f[l][t].zi;    
        else     return f[r-(1<<t)+1][t].zi;
     //   if(line[a].depth<=line[b].depth) return line[a].zi;
      //  else return line[b].zi;
      //  printf("%%%%   %d
    ",t);    
    //    if(ans==f[l][t]) return dfn[l];
    //    else return dfn[r-(1<<t)+1];
    }  
    int main()
    {
        int n;
        n=read();
        int p;
        for(int i=2;i<=n;i++) p=read(),insert(i,p);
        dep[1]=1;
        cnt=0;
        dfs(1);
    //    for(int i=1;i<=n;i++) printf("%d ",dep[i]);
    //    printf("*********
    ");
    //    for(int i=1;i<=cnt;i++)
    //        printf("std:: i : %d zi : %d line : %d tar : %d dfn : %d
    ",i,line[i].zi,line[i].depth,tar[i],dfn[i]);
        lg[1]=0;  
        for(int i=2;i<=cnt;i++)      lg[i]=lg[i>>1]+1;   
        for(int i=1;i<=cnt;i++)  f[i][0].dp=line[i].depth,f[i][0].zi=i;  
          
        int x,y;
        for(int j=1;j<=22;j++)  
        for(int i=1;i<=cnt-( 1<<(j -1) );i++)
        {
            x=f[i][j-1].dp,y=f[ i+( 1<< (j-1) )][ j-1 ].dp;
            if(x<=y) f[i][j].dp=x,f[i][j].zi=f[i][j-1].zi;        
            else     f[i][j].dp=y,f[i][j].zi=f[ i+( 1<< (j-1) )][ j-1 ].zi;
        }    
         
           int m=read();
           int a,b;
           for(int i=1;i<=m;i++)
           {
              a=read(),b=read();
              printf("%d
    ",dfn[lca(a,b)]);
           }
        return 0;
    }
    lca&rmq

    --------------

    还想用tarjian做做(xixi);

  • 相关阅读:
    类加载机制
    PTA(BasicLevel)-1094 谷歌的招聘
    PTA(BasicLevel)-1023 组个最小数
    异构图神经网络笔记-Heterogeneous Graph Neural Network(KDD19)
    PTA(BasicLevel)-1014 福尔摩斯的约会
    PTA(BasicLevel)-1013 数素数
    PTA(BasicLevel)-1012 数字分类
    PTA(BasicLevel)-1010 一元多项式求导
    PTA(BasicLevel)-1009 说反话
    PTA(BasicLevel)-1008数组元素循环右移问题
  • 原文地址:https://www.cnblogs.com/12fs/p/7351755.html
Copyright © 2020-2023  润新知