题目描述
有N (2 <= N <= 1,000)头奶牛,分别编号为1到N。还有N颗牧草分别编号为1到N。简单起见,第i头奶牛都盯着第i颗牧草。有几对牧草分别用一些小路连接了起来,总共有N-1条双向的小路,小路i连接了Ai及Bi颗牧草(1 <= Ai <= N; 1 <= Bi <= N),小路的长度为Li (1 <= Li <= 10,000) 保证任意两颗牧草总能通过小路走到,也就是说这些小路构成了一棵树。奶牛是群居性的动物,很喜欢串门。奶牛们会问你Q次问题(1 <= Q <= 1,000),每次询问的内容很简单,就是从p1颗牧草到p2颗牧草最短的距离是多少。(1 <= p1 <= N; 1 <=p2 <= N)
输入
第一行,两个用空格分隔的整数:N和Q 第二行到第N行,第i+1行包含三个用空格分隔的整数Ai,Bi,Li 第N+1行到第N+Q行,每行包含两个用空格分隔的整数p1,p2
输出
共Q行,每行包含每次询问的最短距离的值。
样例输入
42
2 1 2
4 3 2
1 4 3
1 2
3 2
样例输出
2
7
题解:用LCA求出最近公共祖先,然后子节点不断往上搜即可。
#include <cstdio> #include <cmath> #define N 1005 int a[N][N],first[N*2],next[N*2],v[N*2],dep[N*2],f[N][13]; bool vis[N]; int n,q,x,y,z,cnt,answer,sum; using namespace std; inline void dfs(int root,int k) { vis[root]=1; dep[root]=k; for (int i=first[root];i;i=next[i]) if (!vis[v[i]]) { f[v[i]][0]=root; dfs(v[i],k+1); } } inline int find(int x,int y) { if (dep[x]<dep[y]) { int t=x; x=y; y=t; } for (int i=log2(n);i>=0;i--) if (dep[f[x][i]]>=dep[y]) x=f[x][i]; if (x==y) return x; for (int i=log2(n);i>=0;i--) if (f[x][i]!=f[y][i]) { x=f[x][i]; y=f[y][i]; } return f[x][0]; } int main() { scanf("%d%d",&n,&q); for (int i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&z); a[x][y]=z; a[y][x]=z; next[++cnt]=first[x]; first[x]=cnt; v[cnt]=y; next[++cnt]=first[y]; first[y]=cnt; v[cnt]=x; } dfs(1,1); for (int i=1;i<=log2(n);i++) for (int j=1;j<=n;j++) f[j][i]=f[f[j][i-1]][i-1]; for (int i=1;i<=q;i++) { scanf("%d%d",&x,&y); answer=find(x,y); int j=x; sum=0; while (j!=answer) { sum+=a[j][f[j][0]]; j=f[j][0]; } j=y; while (j!=answer) { sum+=a[j][f[j][0]]; j=f[j][0]; } printf("%d\n",sum); } return 0; }