倍增求lca

 

/*
节点维护的信息多样
如果用树状数组维护到根节点的边权或者点权, 可以直接插入点权和边权值,不需要预处理,
但是记得一定要使用ot[]消除影响.即差分.    Housewife Wind  这个坑踩得死死得.
然后如果带修改,也可以线段树维护.  
打上dfs序后, 其他的就是区间问题了. 然后查询 修改的时候,把dfs序与点或者边对应转换一下就OK了. 
*/ 
int deep[maxn];
int up[maxn][24];
int   in[maxn];  // dfs序 入 
int   ot[maxn];  // dfs序 出 
int   pa[maxn];  // father 数组 
int qsz, qtot;

// 预处理出 deep[] in[] ot[] pa[] up[i][0] 
void dfs(int u, int fa)
{
    int i, v;
    deep[u] = deep[fa] + 1;
    in[u] = qtot;
    for (i=head[u]; i; i=edge[i].lst) {
        v = edge[i].to;
        if (v == fa) continue;
        up[v][0] = u;
        pa[v] = u;
        ++qtot;  // dfs序标号用. 
        dfs(v, u);
    }
    ot[u] = qtot;
}

// 获取公共祖先的表. 
void GetUp(int n)
{
    int i, j;
    for (j=1; j<20; ++j) 
        for (i=1; i<=n; ++i) 
            up[i][j] = up[up[i][j-1]][j-1];
}

// 倍增求lca 
int lca(int u, int v)
{
    if (deep[u] < deep[v]) swap(u, v);
    int i, j, k = deep[u] - deep[v];
    for (i=0; i<20; ++i) // 获取第k个祖先 
        if ((1<<i) & k) 
            u = up[u][i];
    if (u != v) {
        for (i=20; i>=0; --i) 
            if (up[u][i] != up[v][i]) {
                u = up[u][i];
                v = up[v][i];
            }
        u = up[u][0];
    }
    return u;
}

int main()
{
    // 多Cas记得清零 up[][] 之类的数组  还有全局变量 
    deep[0] = 0;
    dfs(1, 0);
    GetUp(n);  // 在dfs()预处理出各节点的父亲后调用. 
    
    return 0;
}

 至于求解答案的几种, 一般也就那几种, 根据维护的信息来画个图,看怎么求解答案. 

 

posted @ 2018-08-17 08:17  过路人1998  阅读(129)  评论(0编辑  收藏  举报