How far away ?
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Problem Description
There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this “How far is it if I want to go from house A to house B”? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path(“simple” means you can’t visit a place twice) between every two houses. Yout task is to answer all these curious people.
Input
First line is a single integer T(T <= 10), indicating the number of test cases.
For each test case,in the first line there are two numbers n(2 <= n <= 40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0 < k <= 40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
Output
For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
Sample Input
2
3 2
1 2 10
3 1 15
1 2
2 3
2 2
1 2 100
1 2
2 1
Sample Output
10
25
100
100
题目大意:一个村子里有n个房子,这n个房子用n-1条路连接起来,接下了有m次询问,每次询问两个房子a,b之间的距离是多少。
很明显的最近公共祖先问题,先建一棵树,然后求出每一点i到树根的距离dis[i],然后每次询问a,b之间的距离=dis[a]+dis[b]-2*dis[LCA(a,b)];
LCA(a,b)即是a,b的最近公共祖先。。
AC代码1:
# include <stdio.h>
# include <string.h>
# include <cmath>
# include <algorithm>
using namespace std;
# define MAXN 400005
struct EDGE
{
int v;
int w;
int next;
}edge[MAXN]; //邻接表存放图结构
int tot;
int head[MAXN];
int vis[MAXN];
int pre[MAXN];
int depth[MAXN];
int dis[MAXN];
int parent[MAXN][25];
void Init()
{
tot = 0;
memset(head, -1, sizeof(head));
}
void Addedge(int u, int v, int w)
{
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
void dfs(int u, int father, int d) //搜索 把图结构装换成树结构
{
depth[u] = d;
pre[u] = father;
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
if (v != father)
{
dis[v] = dis[u] + edge[i].w;
dfs(v, u, d+1);
}
}
}
void LcaInit(int n)
{
int i, j;
for (j = 0; (1 << j) <= n; j++)
{
for (i = 1; i <= n; i++)
{
parent[i][j] = -1;
}
}
for (i = 1; i <= n; i++)
{
parent[i][0] = pre[i];
}
for (j = 1; (1 << j) <= n; j++)
{
for (i = 1; i <= n; i++)
{
if (parent[i][j - 1] != -1)
{
parent[i][j] = parent[parent[i][j - 1]][j - 1];
}
}
}
}
int Lca(int a, int b) //求公共祖先
{
int i, j;
if (depth[a] < depth[b])
{
swap(a, b);
}
for (i = 0; (1 << i) <= depth[a]; i++);
i--;
for (j = i; j >= 0; j--)
{
if (depth[a] - depth[b] >= (1 << j))
{
a = parent[a][j];
}
}
if (a == b)
{
return a;
}
for (j = i; j >= 0; j--)
{
if (parent[a][j] != -1 && parent[a][j] != parent[b][j])
{
a = parent[a][j];
b = parent[b][j];
}
}
return pre[a];
}
int main(void)
{
int t;
int i, j;
scanf("%d", &t);
while (t--)
{
int n, m;
int u, v, w;
scanf("%d %d", &n, &m);
Init();
for (int i = 1; i < n; i++)
{
scanf("%d %d %d", &u, &v, &w);
Addedge(u, v, w);
Addedge(v, u, w);
}
dis[1] = 0;
dfs(1, -1, 0);
LcaInit(n);
int ans = 0;
for (i = 0; i < m; i++)
{
scanf("%d %d", &u, &v);
ans = dis[u] + dis[v] - 2 * dis[Lca(u, v)];
printf("%d\n", ans);
}
}
return 0;
}
AC代码2:
# include <stdio.h>
# include <string.h>
# include <cmath>
# include <vector>
# include <algorithm>
using namespace std;
# define MAXN 40005
struct node{
int v, w;
node(int a = 0, int b = 0){ v = a; w = b; }
};
vector<node> edge[MAXN]; //使用vector容器存放图结构
int vis[MAXN];
int pre[MAXN];
int depth[MAXN];
int dis[MAXN];
int parent[MAXN][25];
void dfs(int u, int father, int d) //图转树
{
depth[u] = d;
pre[u] = father;
int num = edge[u].size();
for (int i = 0; i < num; i++)
{
int v = edge[u][i].v;
if (v != father)
{
dis[v] = dis[u] + edge[u][i].w;
dfs(v, u, d + 1);
}
}
}
void LcaInit(int n)
{
int i, j;
for (j = 0; (1 << j) <= n; j++)
{
for (i = 1; i <= n; i++)
{
parent[i][j] = -1;
}
}
for (i = 1; i <= n; i++)
{
parent[i][0] = pre[i];
}
for (j = 1; (1 << j) <= n; j++)
{
for (i = 1; i <= n; i++)
{
if (parent[i][j - 1] != -1)
{
parent[i][j] = parent[parent[i][j - 1]][j - 1];
}
}
}
}
int Lca(int a, int b)
{
int i, j;
if (depth[a] < depth[b])
{
swap(a, b);
}
for (i = 0; (1 << i) <= depth[a]; i++);
i--;
for (j = i; j >= 0; j--)
{
if (depth[a] - depth[b] >= (1 << j))
{
a = parent[a][j];
}
}
if (a == b)
{
return a;
}
for (j = i; j >= 0; j--)
{
if (parent[a][j] != -1 && parent[a][j] != parent[b][j])
{
a = parent[a][j];
b = parent[b][j];
}
}
return pre[a];
}
int main(void)
{
int t;
int i, j;
scanf("%d", &t);
while (t--)
{
int n, m;
int u, v, w;
scanf("%d %d", &n, &m);
for (i = 1; i <= n; i++)
{
edge[i].clear();
}
for (i = 1; i < n; i++)
{
scanf("%d %d %d", &u, &v, &w);
edge[u].push_back(node(v, w));
edge[v].push_back(node(u, w));
}
dis[1] = 0;
dfs(1, -1, 0);
LcaInit(n);
int ans = 0;
for (i = 0; i < m; i++)
{
scanf("%d %d", &u, &v);
ans = dis[u] + dis[v] - 2 * dis[Lca(u, v)];
printf("%d\n", ans);
}
}
return 0;
}