BZOJ1787: [Ahoi2008]Meet 紧急集合(LCA)

这一道题中,每一次询问的答案就是这三个点,两两的LCA的异或和。至于这样为什么是对的呢?
我们先考虑是否一定有重复的LCA呢?
如果三个点在根节点的不同子树中,那么LCA都是根节点,三个都重复。
如果有两个在一个子树中,那么这两个与另外一个的LCA都是根节点。
如果三个都在一个子树中,可以归纳到以上两种情况。

然后考虑为什么是异或和。
如果三个LCA相同,那么一定是这个点无疑,等于异或和
如果有一个LCA与另外两个不同的时候,肯定要尽量避免两个人走同一段路。因为如果要走到三个点都在的深度最大的子树的根,即相同的LCA,那么必定会有两个人走过同一段路,所以去另一个,每个点都不会走重复的路径

/************************************************************** Problem: 1787 User: geng4512 Language: C++ Result: Accepted Time:1880 ms Memory:20336 kb ****************************************************************/

#include <cstdio>
#define MAXN 500005
struct Node { int v, nxt; } e[MAXN << 1];
int hsn[MAXN], htp[MAXN], sz[MAXN];
int n, m, c, fa[MAXN], dep[MAXN], adj[MAXN];
inline void Add(int u, int v) { ++ c; e[c].v = v; e[c].nxt = adj[u]; adj[u] = c; }
inline void GET(int &n) {
    static char c; n = 0; do c = getchar(); while('0' > c || c > '9');
    do n=n*10+c-'0',c=getchar(); while('0' <= c && c <= '9');
}
void dfs1(int u) {
    sz[u] = 1;
    for(int i = adj[u]; i; i = e[i].nxt) {
        if(sz[e[i].v]) continue;
        dep[e[i].v] = dep[u] + 1;
        fa[e[i].v] = u;
        dfs1(e[i].v);
        sz[u] += sz[e[i].v];
        if(sz[e[i].v] > sz[hsn[u]]) hsn[u] = e[i].v;
    }
}
void dfs2(int u, int tp) {
    htp[u] = tp;
    if(hsn[u]) dfs2(hsn[u], tp);
    for(int i = adj[u]; i; i = e[i].nxt)
        if(!htp[e[i].v]) dfs2(e[i].v, e[i].v);
}
inline int LCA(int u, int v) {
    while(htp[u] != htp[v]) {
        if(dep[htp[u]] > dep[htp[v]]) u = fa[htp[u]];
        else v = fa[htp[v]];
    }
    return dep[u] > dep[v] ? v : u;
}
inline int dis(int u, int v) { return dep[u] - 2*dep[LCA(u, v)] + dep[v]; }
int main() {
    scanf("%d%d", &n, &m); int u, v;
    for(int i = 1; i < n; ++ i) {
        GET(u); GET(v);
        Add(u, v); Add(v, u);
    }
    dfs1(1); dfs2(1, 1);
    int x, y, z, a, b, c;
    for(int i = 1; i <= m; ++ i) {
        GET(a); GET(b); GET(c); x = LCA(a, b);
        y = LCA(b, c); z = LCA(a, c);
        z = x ^ y ^ z;
        printf("%d %d\n", z, dis(a, z) + dis(b, z) + dis(c, z));
    }
    return 0;
}

你可能感兴趣的:(BZOJ1787: [Ahoi2008]Meet 紧急集合(LCA))