How far away ?
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 10764 Accepted Submission(s): 3923
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
这题可以用离线算法做,我这里介绍的是RMQ算法 。。
RMQ算法就是求区间最值问题的算法,这里用到最近公共祖先上面。是根据每个点的编号以及深度来确定最近公共祖先。
贴模板:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; #define N 40010 #define M 205 struct Edge{ int u,v,w,next; }e[2*N]; int head[N]; int dp[2*N][20]; /// int vis[N]; int first[N]; int deep[2*N]; ///记录每个点每次出现出现所在的深度,由于回溯,遂开两倍 int id[2*N]; ///结点的编号,也会出现两次 int dis[N]; int tot; int MIN(int i,int j){ if(i>=j) return j; return i; } void add_edge(int u,int v,int w,int & k){ e[k].u=u;e[k].v=v;e[k].w = w; e[k].next=head[u];head[u]=k++; } void dfs(int u,int d){ vis[u]=true;id[++tot]=u;first[u]=tot;deep[tot]=d; for(int k = head[u];k!=-1;k=e[k].next){ if(!vis[e[k].v]){ int v = e[k].v,w = e[k].w; dis[v]=dis[u]+w; dfs(v,d+1); id[++tot]=u,deep[tot]=d; } } } void init_RMQ(int n){ for(int i=1;i<=n;i++){ dp[i][0]=i; ///保存的是下标 } for(int j=1;(1<<j)<=n;j++){ for(int i=1;i+(1<<j)-1<n;i++){ dp[i][j] = MIN(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } } } int RMQ(int L,int R){ int k=0; while((1<<(k+1))<=(R-L+1)) k++; int a = dp[L][k],b = dp[R-(1<<k)+1][k]; if(deep[a]<deep[b]) return a; return b; } int LCA(int L,int R){ int x = first[L]; int y = first[R]; if(x>y) swap(x,y); return id[RMQ(x,y)]; } int main() { int tcase; scanf("%d",&tcase); while(tcase--){ memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); int n,m; scanf("%d%d",&n,&m); tot = 0; for(int i=1;i<n;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add_edge(u,v,w,tot); add_edge(v,u,w,tot); } tot = 0; dis[1]=0; dfs(1,1); init_RMQ(2*n-1); while(m--){ int a,b; scanf("%d%d",&a,&b); int lca = LCA(a,b); printf("%d\n",dis[a]+dis[b]-2*dis[lca]); } } return 0; }