zoukankan      html  css  js  c++  java
  • CS20 D LCA

    给出一棵树,许多询问,每次询问A,B,C三点,求一点使到三点距离最小,输出该点和最小值。

    很明显就是求LCA,三种组合都求一次LCA,然后在里面选个距离和最小的就行了。

    官方题解里面的代码求LCA是在线DFS RMQ的方法..先记录欧拉序,且记录某个点在序列里的第一个位置,每次询问a,b的LCA就是询问两者在欧拉序列里第一个位置之差中的那些点里面深度最小的

    LCA(a,b)=RMQ(dep, pos[a], pos[b])

    /** @Date    : 2017-09-27 20:41:28
      * @FileName: CS20 C LCA RMQ.cpp
      * @Platform: Windows
      * @Author  : Lweleth (SoungEarlf@gmail.com)
      * @Link    : https://github.com/
      * @Version : $Id$
      */
    #include <bits/stdc++.h>
    #define LL long long
    #define PII pair<int ,int>
    #define MP(x, y) make_pair((x),(y))
    #define fi first
    #define se second
    #define PB(x) push_back((x))
    #define MMG(x) memset((x), -1,sizeof(x))
    #define MMF(x) memset((x),0,sizeof(x))
    #define MMI(x) memset((x), INF, sizeof(x))
    using namespace std;
    
    const int INF = 0x3f3f3f3f;
    const int N = 1e5+20;
    const double eps = 1e-8;
    
    int dep[N];
    int pos[N];
    int rmq[19][2*N];
    int eul[2*N], c, l[2*N];
    
    vector<int> edg[N];
    
    
    void dfs(int x, int pre)
    {
    	eul[++c] = x;
    	pos[x] = c;
    	if(pre) dep[x] = dep[pre] + 1;
    	for(auto i: edg[x])
    	{
    		if(i == pre)
    			continue;
    		dfs(i, x);
    		eul[++c] = x;
    	}
    }
    
    void init()
    {
    	dfs(1, 0);
    	for(int i = 2; i <= c; i++)//预处理 2^k=x对应的k 
    		l[i] = l[i / 2] + 1;
    	for(int i = 1; i <= c; i++)
    		rmq[0][i] = eul[i];
    	for(int j = 1; (1 << j) <= c; j++)
    		for(int i = 1; i <= c; i++)
    		{
    			rmq[j][i] = rmq[j - 1][i];
    			if(i + (1 << (j - 1)) > c)
    				continue;
    			if(dep[rmq[j - 1][i + (1 << (j - 1))]] < dep[rmq[j][i]])
    				rmq[j][i] = rmq[j - 1][i + (1 << (j - 1))];
    		}
    }
    
    int lca(int x, int y)
    {
    	if(pos[x] > pos[y])
    		swap(x, y);
    	int dis = pos[y] - pos[x] + 1;
    	int k = l[dis];
    	if(dep[rmq[k][pos[x] + dis - (1 << k)]] 
    		< dep[rmq[k][pos[x]]])
    		return rmq[k][pos[x] + dis - (1 << k)];
    	else return rmq[k][pos[x]];
    }
    
    int distance(int a, int b)
    {
    	int ac = lca(a, b);
    	return dep[a] + dep[b] - 2 * dep[ac];
    }
    int main()
    {
    	int n, q;
    	cin >> n >> q;
    	for(int i = 0; i < n - 1; i++)
    	{
    		int x, y;
    		scanf("%d%d", &x, &y);
    		edg[x].PB(y);
    		edg[y].PB(x);
    	}
    	init();
    	while(q--)
    	{
    		int a, b, c;
    		scanf("%d%d%d", &a, &b, &c);
    		int ac1 = lca(a, b);
    		int ac2 = lca(a, c);
    		int ac3 = lca(b, c);
    		int ans1 = distance(ac1, a) + distance(ac1, b) + distance(ac1, c);
    		int ans2 = distance(ac2, a) + distance(ac2, b) + distance(ac2, c);
    		int ans3 = distance(ac3, a) + distance(ac3, b) + distance(ac3, c);
    		if(ans1 > ans2)
    			swap(ans1, ans2), swap(ac1, ac2);
    		if(ans1 > ans3)
    			swap(ans1, ans3), swap(ac1, ac3);
    		printf("%d %d
    ", ac1, ans1);
    	}
        return 0;
    }
    
  • 相关阅读:
    用户自定义控件
    sql 动态行转列
    sql 将表B中不存在表A的数据 插入到表A中
    C#获取键盘和鼠标操作的时间的类
    滚动条加粗和panel,gridControl结合用
    第三项任务——用例建模
    第二项任务——项目需求分析
    第一项任务:团队组建及项目启动
    实验报告(结对项目)
    实验报告(个人项目)
  • 原文地址:https://www.cnblogs.com/Yumesenya/p/7604621.html
Copyright © 2011-2022 走看看