URAL 1752. Tree 2 树的直径+LCA倍增

题目来源:URAL 1752. Tree 2

题意:求一个点v与它距离为d的任意一个点 没有输出0

思路:开始想倍增法 但是倍增法只能往他的祖先去 后来百度发现了树的直径 想了想 发现可以建2棵树 每一棵树的根是树的直径的2个端点

这样保证了每个点和他距离最远的点就是其中一个根 因为一个点到树的直径的端点的距离是最远的 最后就是LCA倍增了

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 50010;
const int INF = 0x3f3f3f3f;
int anc[maxn][30][2];
int fa[maxn][2], L[maxn], vis[maxn], d[2][maxn], to[maxn];
int n, m;
int first[maxn], cnt;
struct edge
{
	int u, v, next;
}e[maxn*2];

void AddEdge(int u, int v)
{
	e[cnt].v = v;
	e[cnt].next = first[u];
	first[u] = cnt++;
	e[cnt].v = u;
	e[cnt].next = first[v];
	first[v] = cnt++;
}
void pre()
{
	for(int k = 0; k < 2; k++)
	{
		for(int i = 1; i <= n; i++)
		{
			anc[i][0][k] = fa[i][k];
			for(int j = 1; (1<<j) < n; j++)
				anc[i][j][k] = -1;
		}
		for(int j = 1; (1<<j) < n; j++)
			for(int i = 1; i <= n; i++)
				if(anc[i][j-1][k] != -1)
				{
					int a = anc[i][j-1][k];
					anc[i][j][k] = anc[a][j-1][k];
				}
	}
}

int query(int k, int v, int d)
{
	if(d == 0)
		return v;
	if(d == 1)
		return anc[v][0][k];
	int log = 1;
	for(log = 1; (1<<log) <= d; log++); log--;

	for(int i = log; i >= 0; i--)
	{
		if(d-(1<<i) >= 0)
		{
			d -= (1<<i);
			v = anc[v][i][k];
		}
		if(d == 0)
			return v;
	}
	return 10000;
}

int BFS(int u, int k)
{
	memset(vis, 0, sizeof(vis));
	memset(d[k], 0, sizeof(d[k]));
	vis[u] = 1;
	queue <int> Q;
	Q.push(u);
	int rt = u, dis = -1;
	while(!Q.empty())
	{
		int x = Q.front(); Q.pop();
		if(d[k][x] > dis)
		{
			dis = d[k][x];
			rt = x;
		}
		for(int i = first[x]; i != -1; i = e[i].next)
		{
			int v = e[i].v;
			if(vis[v])
				continue;
			vis[v] = 1;
			d[k][v] = d[k][x] + 1;
			fa[v][k] = x;
			Q.push(v);
		}
	}
	for(int i = 1; i <= n; i++)
		to[i] = max(to[i], d[k][i]);
	return rt;
}
int main()
{
	while(scanf("%d %d", &n, &m) != EOF)
	{
		memset(first, -1, sizeof(first));
		cnt = 0;
		for(int i = 1; i < n; i++)
		{
			int u, v;
			scanf("%d %d", &u, &v);
			AddEdge(u, v);
		}
		memset(to, 0, sizeof(to));
		int s = BFS(1, 0);
		int t = BFS(s, 1);
		BFS(t, 0);
		pre();

		while(m--)
		{

			int v, dis;
			scanf("%d %d", &v, &dis);
			//printf("***%d %d %d\n", to[v], d[0][v], d[1][v]);
			if(to[v] < dis)
			{
				puts("0");
				continue;
			}
			if(d[0][v] > d[1][v])
				printf("%d\n", query(0, v, dis));
			else
				printf("%d\n", query(1, v, dis));
		}
	}
	return 0;
}
时间: 2024-12-24 10:48:52

URAL 1752. Tree 2 树的直径+LCA倍增的相关文章

URAL 1752 Tree 2 树的直径与倍增

假设树的直径的两个端点为p0,p1.如果对于一次询问(v,k)存在点q满足要求,那么q必然在v到p0或v到p1的路径上. 剩下的就是在树上寻找p了.倍增就好了. #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <cmath> #

light oj 1094 Farthest Nodes in a Tree(树的直径模板)

1094 - Farthest Nodes in a Tree PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB Given a tree (a connected graph with no cycles), you have to find the farthest nodes in the tree. The edges of the tree are weighted and undire

lightoj-1094 Farthest Nodes in a Tree(求树的直径)

1094 - Farthest Nodes in a Tree PDF (English) Statistics ForumTime Limit: 2 second(s) Memory Limit: 32 MBGiven a tree (a connected graph with no cycles), you have to find the farthest nodes in the tree. The edges of the tree are weighted and undirect

Lightoj 1094 - Farthest Nodes in a Tree 【树的直径 裸题】

1094 - Farthest Nodes in a Tree PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB Given a tree (a connected graph with no cycles), you have to find the farthest nodes in the tree. The edges of the tree are weighted and undire

SP1437 Longest path in a tree(树的直径)

应该是模板题了吧 定义: 树的直径是指一棵树上相距最远的两个点之间的距离. 方法:我使用的是比较常见的方法:两边dfs,第一遍从任意一个节点开始找出最远的节点x,第二遍从x开始做dfs找到最远节点的距离即为树的直径. 证明:假设此树的最长路径是从s到t,我们选择的点为u.反证法:假设第一遍搜到的点是v. 1.v在这条最长路径上,那么dis[u,v]>dis[u,v]+dis[v,s],显然矛盾. 2.v不在这条最长路径上,我们在最长路径上选择一个点为po,则dis[u,v]>dis[u,po]

Codeforces 1294F Three Paths on a Tree(树的直径,思维)

传送门 题意: 给一个n个结点的无权树,三个结点p1,p2,p3,这三个结点组成的三条路径的路径并集(这个意思就是三条路径之间,重复的边算一次)为ans,找出使得ans最大的三个结点,可能答案有多个,输出一种组合即可 思路: 很显然有种最优解的两个结点为直接的端点p1,p2(直接用两次bfs找直接的端点即可) 然后呢,我们要再找到一个点p3使得,三个点之间的路径的并集最大 我们发现三个点之间的路径的并集即为 \[\frac{dis(p1,p2)+dis(p1,p3)+dis(p2,p3)}{2}

HDU 5296 Annoying Problem 树链剖分 LCA 倍增法

HDU 5296 Annoying Problem 题目链接:hdu 5296 题意:在一棵给定的具有边权的树,一个节点的集合S(初始为空),给定Q个操作,每个操作增加或删除S中的一个点,每个操作之后输出使集合S中所有点联通的最小子树的边权和. 思路:最小子树上的节点的充要条件: 节点为(S集合中所有点的LCA)的子节点: 节点有一个子孙为S集合中的点. 那么我们给每个节点都开一个标记数组,初始为零,每加入一个节点,就把从这个节点到根节点路径上的点的值都+1,反之-1,这样通过对每个单节点值的查

次小生成树(LCA倍增)

算法: 求出MST之后枚举每条在MST之外的边 连上之后会出现环 找到环中除加上的边之外权值最大的边 删除该边之后得到一颗新树 做法: 利用LCA倍增地维护最小生成树上两点之间的最大边权 每次枚举在MST之外的边 有两种情况 ①.两个端点在一条链上 ②.两个端点不在一条链上 第一种情况就直接得到答案 第二种情况的话分两步处理取MAX 复杂度mlogn 严格 bzoj1977 严格的话不仅要处理出maxe[i][j]还要处理出次大的maxe2[i][j] 因为当两点之间的边权最大值等于加上的边权的

CodeForces 379F 树的直径 New Year Tree

题意:每次操作新加两个叶子节点,每次操作完以后询问树的直径. 维护树的直径的两个端点U,V,每次计算一下新加进来的叶子节点到U,V两点的距离,如果有更长的就更新. 因为根据树的直径的求法,若出现新的直径,一定是到U或者到V距离最远. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 const int maxn = 1000000