zoukankan      html  css  js  c++  java
  • P4281 [AHOI2008]紧急集合 / 聚会(最近公共祖先)

    传送门

    • 假设一棵树上要求两个点的到某个点的最短路径,那么可以知道两个点到其两者的LCA距离和一定是最短的。

    • 不难得到,三个点两两相互的LCA点一定有一个是一样的,进而可以发现,如果三个点要去那两个一样的LCA的其中一个,会导致第三个点走重复的路程,这样就不能保证是最短的了。

    • 如果要保证路程最短,那么也就是尽量要减少重复走的路程,可以发现,如果三点同时走那个唯一的LCA,则没有重复路程,这样距离之和就是最短的。

    • 那么如何求最短的距离,对于两个点的距离来说,设两个点分别是a,b,那么其距离为depth[a] + depth[b] - 2 * dep[LCAab]对于这道题的三个点两两求一下就好了。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 5e5 + 10;
    const int M = 1e6 + 10;
    int head[N], tot, n, m, fa[N][22], dep[N];
    
    struct Edge{
    	int v, next;
    }edge[M];
    
    void add(int u, int v){
    	edge[tot].next = head[u];
    	edge[tot].v = v;
    	head[u] = tot ++;
    }
    
    void dfs(int now, int pre){
    	dep[now] = dep[pre] + 1;
    	fa[now][0] = pre;
    	for(int i = head[now]; i != -1; i = edge[i].next){
    		int v = edge[i].v;
    		if(v != pre)
    			dfs(v, now);
    	}
    }
    
    int getlca(int u, int v){
    	if(dep[u] < dep[v])
    		swap(u, v);
    	while(dep[u] != dep[v])
    		u = fa[u][(int)log2(dep[u] - dep[v])];
    	if(u == v)
    		return u;
    	for(int i = 20; i >= 0; i --)
    		if(fa[u][i] != fa[v][i])
    			u = fa[u][i], v = fa[v][i];
    	return fa[u][0];
    }
    
    int main(){
    	scanf("%d%d", &n, &m);
    	memset(head, -1, sizeof head);
    	for(int i = 1; i < n; i ++){
    		int a, b;
    		scanf("%d%d", &a, &b);
    		add(a, b);
    		add(b, a);
    	}	
    	dfs(1, 0);
    	for(int j = 1; j <= 20; j ++)
    		for(int i = 1; i <= n; i ++)
    			fa[i][j] = fa[fa[i][j - 1]][j - 1];
    	
    	for(int i = 1; i <= m; i ++){
    		int a, b, c;
    		scanf("%d%d%d", &a, &b, &c);
    		int lca1 = getlca(a, b);
    		int lca2 = getlca(a, c);
    		int lca3 = getlca(b, c);
    		int unique = 0;
    		if(lca1 == lca2)
    			unique = lca3;
    		else if(lca1 == lca3)
    			unique = lca2;
    		else
    			unique = lca1;
    		int ans = dep[a] + dep[b] + dep[c] - dep[lca1] - dep[lca2] - dep[lca3];
    		printf("%d %d
    ", unique, ans);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    链表--判断一个链表是否为回文结构
    矩阵--“之”字形打印矩阵
    二叉树——平衡二叉树,二叉搜索树,完全二叉树
    链表--反转单向和双向链表
    codeforces 490C. Hacking Cypher 解题报告
    codeforces 490B.Queue 解题报告
    BestCoder19 1001.Alexandra and Prime Numbers(hdu 5108) 解题报告
    codeforces 488A. Giga Tower 解题报告
    codeforces 489C.Given Length and Sum of Digits... 解题报告
    codeforces 489B. BerSU Ball 解题报告
  • 原文地址:https://www.cnblogs.com/pureayu/p/14979659.html
Copyright © 2011-2022 走看看