https://vjudge.net/contest/302013#problem/A
题 意 : 给 定 一 棵 n 个 点 的 树 , m 次 查 询 , 每 次 查 询 3 个 点 , 要 求 这 3 个 点 到 树 上 某 个 点 的 距 离 总 和 最 小 , 输 出 选 定 的 点 和 距 离 题意:给定一棵n个点的树,m次查询,每次查询3个点,要求这3个点到树上某个点 的距离总和最小,输出选定的点和距离 题意:给定一棵n个点的树,m次查询,每次查询3个点,要求这3个点到树上某个点的距离总和最小,输出选定的点和距离
题 解 : L C A ( 最 近 公 共 祖 先 ) 题解:LCA(最近公共祖先) 题解:LCA(最近公共祖先)
可 以 发 现 , 给 定 3 个 点 , 那 么 L C A 也 有 3 个 , 但 是 必 定 有 两 个 L C A 是 相 同 的 , 那 么 我 们 就 要 选 择 另 外 一 个 不 同 的 L C A 作 为 答 案 , 然 后 求 距 离 就 好 了 。 可以发现,给定3个点,那么LCA也有3个,但是必定有两个LCA是相同的,那么我们就要选择另外一个不同的LCA作为答案,然后求距离就好了。 可以发现,给定3个点,那么LCA也有3个,但是必定有两个LCA是相同的,那么我们就要选择另外一个不同的LCA作为答案,然后求距离就好了。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#include<vector>
using namespace std;
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define mem(a,b) memset(a,b,sizeof(a));
#define lowbit(x) x&-x;
#define debugint(name,x) printf("%s: %d\n",name,x);
#define debugstring(name,x) printf("%s: %s\n",name,x);
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int mod = 1e9+7;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN = 10010;
const int DEG = 20;
struct Edge
{
int to,next;
}edge[MAXN*2];
int head[MAXN],tot;
void addedge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
}
int fa[MAXN][DEG];
int deg[MAXN];
void BFS(int root)
{
queue<int>que;
deg[root] = 0;
fa[root][0] = root;
que.push(root);
while(!que.empty())
{
int tmp = que.front();
que.pop();
for(int i = 1;i < DEG;i++)
fa[tmp][i] = fa[fa[tmp][i-1]][i-1];
for(int i = head[tmp]; i != -1;i = edge[i].next)
{
int v = edge[i].to;
if(v == fa[tmp][0])continue;
deg[v] = deg[tmp] + 1;
fa[v][0] = tmp;
que.push(v);
}
}
}
int LCA(int u,int v)
{
if(deg[u] > deg[v])swap(u,v);
int hu = deg[u], hv = deg[v];
int tu = u, tv = v;
for(int det = hv-hu, i = 0; det ;det>>=1, i++)
if(det&1)
tv = fa[tv][i];
if(tu == tv)return tu;
for(int i = DEG-1; i >= 0; i--)
{
if(fa[tu][i] == fa[tv][i])
continue;
tu = fa[tu][i];
tv = fa[tv][i];
}
return fa[tu][0];
}
int dis(int u,int v){
int lca = LCA(u,v);
return deg[u]+deg[v]-2*deg[lca];
}
int n,m;
int main(){
scanf("%d%d",&n,&m);
int u,v;
init();
for(int i = 1; i <= n-1; i++){
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
BFS(1);
int x,y,z,ans;
while(m--){
scanf("%d%d%d",&x,&y,&z);
int l1 = LCA(x,y), l2 = LCA(x,z), l3 = LCA(y,z);
if(l1 == l2){
printf("%d ",l3);
ans = dis(x,l3)+dis(y,l3)+dis(z,l3);
printf("%d\n",ans);
}
else if(l1 == l3){
printf("%d ",l2);
ans = dis(x,l2)+dis(y,l2)+dis(z,l2);
printf("%d\n",ans);
}
else if(l2 == l3){
printf("%d ",l1);
ans = dis(x,l1)+dis(y,l1)+dis(z,l1);
printf("%d\n",ans);
}
}
}
博客围绕vjudge上的一道题展开,题目给定一棵n个点的树,进行m次查询,每次查询3个点,需找出使这3个点到树上某点距离总和最小的点并输出该点和距离。题解采用LCA(最近公共祖先)方法,利用3个点有3个LCA且必有两个相同的特性,选择不同的LCA作为答案来求解。
1002

被折叠的 条评论
为什么被折叠?



