HDU 6031 Innumerable Ancestors (LCA)

7 篇文章 0 订阅

There is a tree having n nodes, labeled from 1 to n. The root of the tree is always 1, and the depth of a node p is the number of nodes on the shortest path between node p and the root.
In computer science, the Lowest Common Ancestor (LCA) of two nodes v and w in a tree is the lowest (i.e. deepest) node that has both v and w as descendants, where we define each node to be a descendant of itself (so if v has a direct connection from w, w is the lowest common ancestor).
You have to answer m queries. Each query gives two non-empty node sets A and B, there might be some nodes in both sets.
You should select one node x from set A, and one node y from set B, x and y can be the same node. Your goal is to maximize the depth of the LCA of x and y.
Please write a program to answer these queries.

题意

给定 N 节点的树,问集合 A 中节点 x 与集合 B 中节点 y 的 LCA(x, y) 的深度的最大值。

解题思路

根据 DFS 序,若两个点的 DFS 序越接近,则两个点的 LCA 的深度越大。

故可将集合 A 与集合 B 中的点分别按照 DFS 序排序。遍历集合 A 中所有元素,对任意一个元素 x,在集合 B 中二分查找与其 DFS 序最接近的点 y1, y2 (DFS 序大于等于 x 及 DFS 序小于 x)。利用 LCA 算法 O(logN) 求取 LCA(x, y1) , LCA(x, y2) ,并取深度的最大值即可。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 100000 + 10;
const int maxh = 20; //log2(N);
struct Edge {
    int to, nxt;
} e[N*2];
int head[N], cnt;
void addedge(int u, int v) {
    e[++cnt].nxt = head[u];
    e[cnt].to = v;
    head[u] = cnt;
}
int id[N], idx, a[N], b[N], n, m;
void genId(int rt, int pre) {
    id[rt] = ++idx;
    for(int i=head[rt];i;i=e[i].nxt) {
        if(e[i].to == pre)  continue;
        genId(e[i].to, rt);
    }
}
bool cmp(int a, int b) {
    return id[a] < id[b];
}
int dep[N], anc[N][20];
void dfs(int rt) {
    static int Stack[N];
    int top = 0;
    dep[rt] = 1;
    for(int i=0;i<maxh;i++)
        anc[rt][i] = rt;
    Stack[++top] = rt;
    while(top) {
        int x = Stack[top];
        if(x != rt) {
            for(int i=1, y;i<maxh;i++)
                y = anc[x][i-1],    anc[x][i] = anc[y][i-1];
        }
        for(int &i=head[x];i;i=e[i].nxt) {
            int y = e[i].to;
            if(y != anc[x][0]) {
                dep[y] = dep[x] + 1;
                anc[y][0] = x;
                Stack[++top] = y;
            }
        }
        while(top && head[Stack[top]] == 0) top--;
    }
}
void swim(int &x, int H) {
    for(int i=0;H;i++) {
        if(H & 1)   x = anc[x][i];
        H /= 2;
    }
}
int lca(int x, int y) {
    int i;
    if(dep[x] > dep[y]) swap(x, y);
    swim(y, dep[y]-dep[x]);
    if(x == y)  return x;
    for(;;) {
        for(i=0;anc[x][i] != anc[y][i];i++);
        if(i == 0)  return anc[x][0];
        x = anc[x][i-1];
        y = anc[y][i-1];
    }
    return -1;
}
void init() {
    memset(head, 0, sizeof(head));
    cnt = 0;    idx = 0;
}
int main()
{
    while(scanf("%d %d", &n, &m)!=EOF)
    {
        init();
        for(int i=1, u, v;i<n;i++)
            scanf("%d %d",&u,&v),
            addedge(u, v),
            addedge(v, u);
        genId(1, -1);
        dfs(1);
        for(int i=1, ka, kb;i<=m;i++)
        {
            scanf("%d",&ka);
            for(int j=0;j<ka;j++)
                scanf("%d",&a[j]);
            sort(a, a+ka, cmp);
            scanf("%d",&kb);
            for(int j=0;j<kb;j++)
                scanf("%d",&b[j]);
            sort(b, b+kb, cmp);

            int ans = 0;
            for(int j=0, pos;j<ka;j++)
            {
                pos = lower_bound(b, b+kb, a[j], cmp) - b;
                if(pos < kb)
                    ans = max(ans, dep[lca(a[j], b[pos])]);
                if(--pos >= 0)
                    ans = max(ans, dep[lca(a[j], b[pos])]);
            }
            printf("%d\n", ans);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值