首页 > 代码库 > URAL 1752. Tree 2 树的直径+LCA倍增

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;
}


 

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