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;
    }
    
  • 相关阅读:
    vivim (十一):文本重排
    vivim (十):接出(复制)
    python的函数
    从oracle11g向oracle9i导数据遇到的一些问题
    vivim (十二):中介字元正则表达式
    DataList如何实现横向排列数据交替行变色!
    跳出率对百度排名的影响越来越大
    asp.net 服务器端控件使用服务器端变量
    .net .用户控件和页面的加载顺序、生命周期
    网站如何让被DOMZ收录
  • 原文地址:https://www.cnblogs.com/pureayu/p/14979659.html
Copyright © 2011-2022 走看看