树,LCA,最近公共祖先,倍增

最近公共祖先,

树上倍增,LCA,

fa [ i ] [ j ] 表示 i 节点向上 2j 的祖先

很像dp,

k 属于 [ 1 , log ( n ) ] ,f [ x ][ k ] = f [ f [ x ] [ k-1 ]] [k-1]

算lca时,

先不妨设 d [ x ] >= d [ y ]

二进制拆分

尝试从x 向上走 k = 2log (n),~~,21,20,

检查到的点是否比 y 深

每次检查中,若是,x= f [ x ] [ k ]

若仍未相会, 即 f [ x ] [ k ] != f [ y ] [ k ]

令 x = f [ x ] [ k ], y = f [ y ] [ k ]

最后,若 x = y , lca ( x , y )=y

看看代码

#include <cstdio>
#include <iostream>
#include <string>
#include <bits/stdc++.h>

using namespace std;
#define MAXN 50010
int fa[MAXN][20];
//f[i][j]表示i的2^j的祖先
int dep[MAXN];//深度
int dis[MAXN];//到根节点距离

struct edge {
    int v;
    int w;
    int nxt;
} e[MAXN*2];
int head[MAXN];
int T,n,m,cnt;
int t;//指数次幂 t=(log(n)/log(2))+1

void add(int x,int y,int z) {
    e[++cnt].v=y;
    e[cnt].w=z;
    e[cnt].nxt=head[x];
    head[x]=cnt;
}
queue<int> q;
void bfs() {
    //预处理
    q.push(1);
    dep[1]=1;
    while (q.size()) {
        int x=q.front();
        q.pop();
        for (int i=head[x]; i; i=e[i].nxt) {
            int y=e[i].v;
            if (dep[y]) continue;
            dep[y]=dep[x]+1;
            dis[y]=dis[x]+e[i].w;
            fa[y][0]=x;
            for (int j=1; j<=t; j++) {
                fa[y][j]=fa[fa[y][j-1]][j-1];
            }
            q.push(y);
        }
    }
}

int lca(int x,int y) {
    if (dep[x]>dep[y]) swap(x,y);
    for (int i=t; i>=0; i--) {
        if (dep[fa[y][i]]>=dep[x]) {
            y=fa[y][i];
        }
    }
    if (x==y) return x;
    for (int i=t; i>=0; i--) {
        if (fa[x][i]!=fa[y][i]) {
            x=fa[x][i];
            y=fa[y][i];
        }
    }
    return fa[y][0];
}


int main () {
    memset(head,0,sizeof(head));
    memset(dep,0,sizeof(dep));
    cnt=0;
    cin>>n>>m;
    t=(int)(log(n)/log(2))+1;
    //cout<<t<<endl;
    for (int i=1,x,y,z; i<n; i++) {
        cin>>x>>y>>z;
        add(x,y,z);
        add(y,x,z);
    }

    bfs();/*
    for (int i=1; i<=n; i++) {
        cout<<dep[i]<<" ";
    }
    cout<<endl;
    for (int i=1; i<=n; i++) {
        cout<<dis[i]<<" ";
    }
    cout<<endl;*/
    for (int i=1,x,y,len; i<=m; i++) {
        //询问
        cin>>x>>y;
        int k;
        k=lca(x,y);
        cout<<k<<endl;
        len=dis[x]+dis[y]-2*dis[k];
        cout<<len<<endl;
    }
    return 0;
}

/*
10 5
1 2 2
1 3 4
2 4 3
2 5 7
3 6 2
3 7 4
4 8 2
5 9 3
6 10 1
6 7
9 3
8 5
10 6
4 7
*/

 

 还有一种:

    
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,q,cnt;
int deep[1001],head[1001],dis[1001],fa[1001][11];
bool vis[1001];
struct data{int to,next,v;}e[2001];
void ins(int u,int v,int w)
{e[++cnt].to=v;e[cnt].next=head[u];e[cnt].v=w;head[u]=cnt;}
void insert(int u,int v,int w)
{ins(u,v,w);ins(v,u,w);}
void dfs(int x)
{
    vis[x]=1;
    for(int i=1;i<=9;i++)
    {
        if(deep[x]<(1<<i))break;
        fa[x][i]=fa[fa[x][i-1]][i-1];
    }
    for(int i=head[x];i;i=e[i].next)
    {
        if(vis[e[i].to])continue;
        deep[e[i].to]=deep[x]+1;
        dis[e[i].to]=dis[x]+e[i].v;
        fa[e[i].to][0]=x;
        dfs(e[i].to);
    }
}
int lca(int x,int y)
{
    if(deep[x]<deep[y])swap(x,y);
    int d=deep[x]-deep[y];
    for(int i=0;i<=9;i++)
       if((1<<i)&d)x=fa[x][i];
    for(int i=9;i>=0;i--)
       if(fa[x][i]!=fa[y][i]) 
          {x=fa[x][i];y=fa[y][i];}
    if(x==y)return x;
    else return fa[x][0];
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<n;i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        insert(u,v,w);
    }
    dfs(1);
    for(int i=1;i<=q;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%d\n",dis[x]+dis[y]-2*dis[lca(x,y)]);
    }
    return 0;
}

 

OK啦

 

posted @ 2018-10-12 20:05  codemaker_li  阅读(135)  评论(0编辑  收藏  举报