• [CF Round #294 div2] E. A and B and Lecture Rooms 【树上倍增】


    题目链接:E. A and B and Lecture Rooms

    题目大意

    给定一颗节点数10^5的树,有10^5个询问,每次询问树上到xi, yi这两个点距离相等的点有多少个。

    题目分析

    若 x==y 直接返回 n。

    先求出 x, y 两个点的中点。

    先求出 LCA(x, y) = z,假设 Depth[x] >= Depth[y] ,若Depth[x] == Depth[y] ,那么 z 就是它们的中点。

    答案就是,n - Size[fx] - Size[fy],fx 是从x向上跳,一直跳到 z 的一个孩子就停止,这个孩子就是 fx。

    否则中点一定在从 x -- z -- y 的路径上 x -- z 的一段,为 Jump(x, t) ,t 是 x -- z -- y 长度的一半。如果 x -- z -- y 的长度是奇数,就返回 0。

    这个 Jump(a, b) 就是用倍增来求的。

    答案就是, Size[o] - Size[fx]。这里的o是中点,fx是从x向上跳,跳到o的一个孩子就停止。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    
    const int MaxN = 100000 + 5, MaxLog = 19 + 5;
    
    int n, m;
    int Depth[MaxN], Father[MaxN], Jump[MaxN][MaxLog], Size[MaxN];
    
    struct Edge
    {
    	int v;
    	Edge *Next;
    } E[MaxN * 2], *P = E, *Point[MaxN];
    
    inline void AddEdge(int x, int y) 
    {
    	++P; P -> v = y;
    	P -> Next = Point[x]; Point[x] = P;
    }
    
    void DFS(int x, int Dep, int Fa) 
    {
    	Depth[x] = Dep;
    	Father[x] = Fa;
    	Size[x] = 1;
    	for (Edge *j = Point[x]; j; j = j -> Next) 
    	{
    		if (j -> v == Father[x]) continue;
    		DFS(j -> v, Dep + 1, x);
    		Size[x] += Size[j -> v];
    	}
    }
    
    void Prepare() 
    {
    	for (int i = 1; i <= n; ++i) Jump[i][0] = Father[i];
    	for (int i = 1; i <= n; ++i) 
    		for (int j = 1; j <= 18; ++j) 
    			Jump[i][j] = Jump[Jump[i][j - 1]][j - 1];
    }
    
    int JumpUp(int x, int y) 
    {
    	int ret = x;
    	for (int i = 0; i <= 18; ++i)	
    		if (y & (1 << i)) ret = Jump[ret][i];
    	return ret;
    }
    
    int LCA(int x, int y) 
    {
    	if (Depth[x] < Depth[y]) swap(x, y);
    	int Dif;
    	Dif = Depth[x] - Depth[y];
    	if (Dif) x = JumpUp(x, Dif);
    	if (x == y) return x;
    	for (int i = 18; i >= 0; --i) 
    	{
    		if (Jump[x][i] != Jump[y][i]) 
    		{
    			x = Jump[x][i];
    			y = Jump[y][i];
    		}
    	}
    	return Father[x];
    }
    
    int Query(int x, int y) 
    {
    	if (x == y) return n;
    	if (Depth[x] < Depth[y]) swap(x, y);
    	int z, tx, ty, fx, fy, t, o;
    	z = LCA(x, y);
    	tx = Depth[x] - Depth[z];
    	ty = Depth[y] - Depth[z];
    	t = tx + ty;	
    	if (t & 1) return 0;
    	if (Depth[x] == Depth[y]) 
    	{
    		fx = JumpUp(x, tx - 1);
    		fy = JumpUp(y, ty - 1);
    		return n - Size[fx] - Size[fy];
    	}
    	else 
    	{
    		t >>= 1;
    		o = JumpUp(x, t);
    		fx = JumpUp(x, t - 1);
    		return Size[o] - Size[fx];
    	}
    }
    
    int main()
    {
    	scanf("%d", &n);
    	int a, b;
    	for (int i = 1; i <= n - 1; ++i) 
    	{
    		scanf("%d%d", &a, &b);
    		AddEdge(a, b);
    		AddEdge(b, a);
    	}
    	scanf("%d", &m);
    	DFS(1, 0, 0);
    	Prepare();
    	for (int i = 1; i <= m; ++i) 
    	{
    		scanf("%d%d", &a, &b);
    		printf("%d
    ", Query(a, b));
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    数据结构与算法分析-二叉堆
    数据结构与算法分析-AVL树
    数据结构与算法分析-二叉查找树
    优秀程序员应具备的15个特性
    2016年1月22日 收盘后美加的走势
    2016年1月8日 12月非农数据
    Replace into 与Insert into on duplicate key update的区别
    MYSQL视图的学习笔记
    postgresql创建用户
    连接postgresql数据库
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4311108.html
Copyright © 2020-2023  润新知