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%的数据:1\leq 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\n",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("\n**** %d %d\n",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\n",l,r) ;
    int t=lg[r-l+1];  
  //  printf("$ $$ $ : %d %d\n",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\n",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("*********\n");
//    for(int i=1;i<=cnt;i++)
//        printf("std:: i : %d zi : %d line : %d tar : %d dfn : %d\n",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\n",dfn[lca(a,b)]);
       }
    return 0;
}
lca&rmq

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

还想用tarjian做做(xixi);

 

posted @ 2017-08-12 21:56  12fs  阅读(291)  评论(0编辑  收藏  举报