问题 C: 牧场行走
时间限制: 1 Sec 内存限制: 128 MB提交: 74 解决: 36
[提交][状态][讨论版]
题目描述
农场主奶牛有N个约翰,被标记为1到n,在同样被标记1到n的n块土地上吃草,第i头约翰在第i块牧场吃草。 这n块土地被n-1条路连接。 约翰可以在路上行走,第i条路连接第Ai,Bi块牧场,第i条路的长度是Li这些路被安排成任意两个约翰都可以通过这些路到达的情况,所以说这是一棵树。 这些约翰是非常喜欢交际的,经常会去互相访问,他们想让你去帮助他们计算Q对约翰之间的距离。
输入
第一行:两个被空格隔开的整数:N和Q
第二行到第n行:第i+1行有两个被空格隔开的整数:Ai,Bi,Li
第n+1行到n+Q行:每一行有两个空格隔开的整数:P1,P2,表示两头奶牛的编号。
输出
第1行到第Q行:每行输出一个数,表示那两头奶牛之间的距离。
样例输入
5 3
2 1 1
3 2 2
4 1 4
5 2 8
3 4
3 5
4 5
样例输出
7
10
13
提示
2<=n,q<=1000
题解:树上倍增lca,求树上两节点a、b的距离即为dis[a]+dis[b]-2*dis[lca(a,b)](其中dis表示该节点到根的距离)。
代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #define maxpow 10 5 using namespace std; 6 int n,p,fa[12][1005],dep[1005],dis[1005]; 7 int cnt,head[1005]; 8 bool vis[1005]; 9 struct edge{int to,next,val;}e[2005]; 10 void ins(int x,int y,int v){e[++cnt].to=y;e[cnt].next=head[x];head[x]=cnt;e[cnt].val=v;} 11 void dfs(int u){ 12 vis[u]=true; 13 for(int i=1;i<maxpow;i++) 14 if(dep[u]<(1<<i)) break; 15 else fa[i][u]=fa[i-1][fa[i-1][u]];//倍增操作 16 for(int i=head[u];i;i=e[i].next){ 17 int v=e[i].to; 18 if(vis[v]) continue; 19 dep[v]=dep[u]+1; dis[v]=dis[u]+e[i].val; 20 fa[0][v]=u; dfs(v); 21 } 22 } 23 int lca(int u,int v){ 24 if(dep[u]<dep[v]) swap(u,v); 25 int dif=dep[u]-dep[v]; 26 for(int i=0;i<maxpow;i++) if((1<<i)&dif) u=fa[i][u];//u向上移动至于v同一深度 27 if(u==v) return u; 28 for(int i=maxpow-1;i>=0;i--) 29 if(fa[i][u]!=fa[i][v]){u=fa[i][u]; v=fa[i][v];}//u、v同时倍增 30 return fa[0][u];//注意这里返回fa 31 } 32 int main() 33 { 34 scanf("%d%d",&n,&p); 35 for(int i=1;i<n;i++){ 36 int x,y,l; 37 scanf("%d%d%d",&x,&y,&l); 38 ins(x,y,l); ins(y,x,l); 39 } 40 dfs(1); 41 for(int i=1;i<=p;i++){ 42 int x,y; scanf("%d%d",&x,&y); 43 printf("%d ",dis[x]+dis[y]-2*dis[lca(x,y)]); 44 } 45 return 0; 46 }