复制代码

lca 最近公共祖先 倍增

每日一算,公共祖先问题

  分类 单根,那么 直接 dfs(root)

#include<bits/stdc++.h>
using namespace std;
#define LOACL  freopen("in","r",stdin);\
         freopen("out","w",stdout); 
#define FOR(i, a, b)  for(int i=(a); i<(b); i++)
#define REP(i, a, b)  for(int i=(a); i<=(b); i++)
#define DOWN(i, a, b) for(int i=(a); i>=(b); i--)
#define sz 1000100
#define demen 21

int n,m,s,tot,u,v,head[sz],fa[sz][demen],d[sz];
struct node
{int t,nxt;}e[sz];
void add(int u,int v)
{ e[++tot]=(node){v,head[u]},head[u]=tot;}

void dfs(int rt,int f)
{
    d[rt] =d[f]+1;
    fa[rt][0] = f;
    REP(i,1,20)
        fa[rt][i] =fa[fa[rt][i-1]][i-1];
    for(int i=head[rt];i;i=e[i].nxt)
         if(e[i].t!=f)
            dfs(e[i].t,rt);
}
int lca(int x,int y)
{
    if(d[x]<d[y])swap(x,y);

    int dre = d[x] - d[y];
    DOWN(i,20,0)
        if((1<<i)&dre)
            x = fa[x][i];
    if(x==y)return x;
    DOWN(i,20,0)
    if(fa[x][i]!=fa[y][i])
        x = fa[x][i],y=fa[y][i];
    return fa[x][0];
}


int main()
{
    //LOACL
     ios::sync_with_stdio(false);
 
    cin>>n>>m>>s;    
    REP(i,1,n-1)
    {
        cin>>u>>v;
          
          add(u,v),add(v,u);           
    }
    dfs(s,0);
    REP(i,1,m)
    { 
        cin>>u>>v;
        
          printf("%d\n",lca(u,v));
    } 
    return 0;
}
View Code

  多个根 那么就记搜

#include<bits/stdc++.h>
using namespace std;
#define LOACL  freopen("in","r",stdin);\
         freopen("out","w",stdout); 
#define FASTIO  ios::sync_with_stdio(false);
#define CLR(arr,val) memset(arr,val,sizeof(arr)) 
#define DBG(x) cout<<(#x)<<"="<<x<<endl
#define DBG2(x,y) cout<<(#x)<<"="<<x<<"\t"<<(#y)<<"="<<y<<endl
#define DBG3(x,y,z) cout<<(#x)<<"="<<x<<"\t"<<(#y)<<"="<<y<<"\t"<<(#z)<<"="<<z<<endl
 
#define FOR(i, a, b)  for(int i=(a); i<(b); i++)
#define REP(i, a, b)  for(int i=(a); i<=(b); i++)
#define DOWN(i, a, b) for(int i=(a); i>=(b); i--)

#define INF 999999999
const int sz = 30000*2;
int n,m,x,y,z,tot,q;
int head[sz],deep[sz],fa[sz],f[sz][21],w[sz][21];
bool vis[sz];
struct node
{
    int u,v,w; 
}a[sz];
struct edge
{
    int v,nxt,w;
}e[sz<<1];
bool cmp(node l ,node r)
{
    return l.w>r.w;
}
int getf(int x)
{
    if(x!=fa[x])fa[x]=getf(fa[x]);
    return fa[x];
}
void add(int u ,int v,int w )
{
      e[++tot] =(edge){v,head[u],w},head[u]=tot;
    e[++tot] =(edge){u,head[v],w},head[v]=tot;
}

void krusual()
{
    sort(a+1,a+m+1,cmp);
    REP(i,1,n) fa[i]=i; 
    REP(i,1,m)
    {
        if(getf(a[i].u)!=getf(a[i].v))
        {
            fa[getf(a[i].u)] = getf(a[i].v);
            add(a[i].u,a[i].v,a[i].w);
        }    
    }
}
 
void dfs(int x)
{
    vis[x] = true;
    for(int i = head[x];i;i=e[i].nxt)
    {
        int v = e[i].v;
        if(vis[v]) continue;
        deep[v] =deep[x]+1;
        f[v][0] = x;
        w[v][0] = e[i].w;
        dfs(v); 
    }
}
int lca (int x,int y)
{  
 
    if(getf(x)!=getf(y)) return -1;
    int ans=INF;
    if(deep[x]<deep[y])swap(x,y);

    DOWN(i,20,0)
        if(deep[f[x][i]]>=deep[y])
        {
            
            ans=min(ans,w[x][i]);
            x = f[x][i];
        }    


    if(x==y) return ans;
 
    DOWN(i,20,0)
    {
        if(f[x][i]!=f[y][i])
        {
            ans=min(ans,min(w[x][i],w[y][i]));
            x=f[x][i],y=f[y][i];
        }
    }    
     ans = min(ans,min(w[x][0],w[y][0]));
    return ans;

}

int lca1(int x,int y)
{
    if(getf(x)!=getf(y)) return -1;
    int ans=INF;
    if(deep[x]>deep[y]) swap(x,y);
    DOWN(i,20,0)
    {
        if(deep[f[y][i]] >=deep[x])
        {
            ans = min(ans,w[y][i]);
            y=f[y][i];
        }
    }
    if(x==y) return ans; 
    DOWN(i,20,0)
    {
        if(f[x][i]!=f[y][i])
        {
            ans=min(ans,min(w[x][i],w[y][i]));
            x=f[x][i],y=f[y][i];
        }
    }
    ans = min(ans,min(w[x][0],w[y][0]));
    return ans;
}


int main()
{
    LOACL
    FASTIO
    cin>>n>>m;
    REP(i,1,m)
        cin>>a[i].u>>a[i].v>>a[i].w;
     krusual();

     //先 dfs 一下 然后 init lca 
     REP(i,1,n)
     {
         if(!vis[i])
         {
             deep[i]=1;
             dfs(i);
             f[i][0]=i;
             w[i][0]=INF;
         }
     }

 //   REP(i,1,n) DBG3(i,f[i][0],w[i][0]);

     REP(j,1,20) REP(i,1,n)
     {
         f[i][j] =f[f[i][j-1]][j-1];
         w[i][j] =min(w[i][j-1],w[f[i][j-1]][j-1]);    
     }
     //REP(i,1,n) DBG3( w[i][0],f[i][0], deep[i]);
     cin>>q;
     REP(i,1,q)
     {
         cin>>x>>y;
         cout<<lca(x,y)<<endl;
     } 

    return 0;
}
View Code

  涉及到一个lca(x,y) 这个函数 的注意事项:

  需要的 核心跳转 倍增思想,什么意思呢,记得做填那个神奇算法,硬币分包问题吗?

  2^i 会产生对2^(i+1) 影响跳转 ,是不是很神奇,一下子就 砍到了 lg(n) 完全符合算法的思维,n===>lgn 的进化.

  

posted @ 2018-04-13 22:04  pg633  阅读(141)  评论(0编辑  收藏  举报