1. 程式人生 > >【9018:1893】牧場行走

【9018:1893】牧場行走

bool dfs 一個數 倍增 個數 輸入 online 通過 problem

問題 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\n",dis[x]+dis[y]-2*dis[lca(x,y)]); 44 } 45 return 0; 46 }

【9018:1893】牧場行走