树上三点间距离

P4281 [AHOI2008]紧急集合 / 聚会

这道题很卡常

但用一些优化 可过

问题

求一点到 三个不同点的距离最小

输出这个点 和这个距离

#define sum(a,b,c) (depth[a] + depth[b] + depth[c])
t,ab = lca(a,b),ac = lca(a,c),bc = lca(b,c);
if(ab == ac) t = bc;
if(ab == bc) t = ac;
if(ac == bc) t = ab;
printf("%d %d
",t,sum(a,b,c) - sum(ab,ac,bc));

感性理解下

倍增的一些优化

for(reg i = 1;i <= n;i++) 
        lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
        
inline int lca(int a,int b)
{
	if(depth[a] < depth[b]) swap(a,b);
	while(depth[a] > depth[b]) a = fa[a][lg[depth[a] - depth[b]] - 1];
	if(a == b) return a;
	for(reg i = lg[depth[a]];i >= 0;i--)
		if(fa[a][i] != fa[b][i])
			a = fa[a][i],b = fa[b][i];
	return fa[a][0];
}

总结

  • 少函数,非递归函数用宏

  • (lca),提前处理(log)

  • register int

  • 变量名尽量小写,短

(Code)


#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define reg register int
const int MAXN = 5e5 + 10;
int cnt,fa[MAXN][30],lg[MAXN],head[MAXN],depth[MAXN],n,m;
bool vis[MAXN];
struct node
{
	int v,next;
}edge[MAXN << 1];
template<typename T>
inline T Read(T Type)
{
	T x = 0;
	bool f = 0;
	char a = getchar();
	while(!isdigit(a)) {if(a == '-') f = 1;a = getchar();}
	while(isdigit(a)) x = (x << 1) + (x << 3) + a - '0',a = getchar();
	if(f) x *= -1;
	return x;
}
inline void addedge(int u,int v)
{
	edge[++cnt].v = v;
	edge[cnt].next = head[u];
	head[u] = cnt;
}
inline void prepare(int x)
{
	vis[x] = 1;
	for(reg i = head[x];i;i = edge[i].next)
	{
		int v = edge[i].v;
		if(vis[v]) continue;
		fa[v][0] = x;
		depth[v] = depth[x] + 1;
		prepare(v);
	}
}
inline int lca(int a,int b)
{
	if(depth[a] < depth[b]) swap(a,b);
	while(depth[a] > depth[b]) a = fa[a][lg[depth[a] - depth[b]] - 1];
	if(a == b) return a;
	for(reg i = lg[depth[a]];i >= 0;i--)
		if(fa[a][i] != fa[b][i])
			a = fa[a][i],b = fa[b][i];
	return fa[a][0];
}
#define sum(a,b,c) (depth[a] + depth[b] + depth[c])
int main()
{
	n = Read(1),m = Read(1);
	for(reg i = 1;i < n;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		addedge(u,v),addedge(v,u);
	}
	fa[1][0] = 1;
	for(reg i = 1;i <= n;i++) 
        lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
	prepare(1);
	for(reg i = 1;i <= lg[n];i++)
		for(reg j = 1;j <= n;j++)
			fa[j][i] = fa[fa[j][i - 1]][i - 1];
	int t,a,b,c,ab,ac,bc;
	for(reg i = 1;i <= m;i++)
	{
		a = Read(1),b = Read(1),c = Read(1),t,ab = lca(a,b),ac = lca(a,c),bc = lca(b,c);
		if(ab == ac) t = bc;
		if(ab == bc) t = ac;
		if(ac == bc) t = ab;
		printf("%d %d
",t,sum(a,b,c) - sum(ab,ac,bc));
	}
	return 0;
}

原文地址:https://www.cnblogs.com/resftlmuttmotw/p/11783159.html