商务旅行
时间限制: 1 s
空间限制: 128000 KB
题目描述 Description
某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间。
假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有直连道路,在他们之间行驶需要花费单位时间。该国公路网络发达,从首都出发能到达任意一个城镇,并且公路网络不会存在环。
你的任务是帮助该商人计算一下他的最短旅行时间。
输入描述 Input Description
输入文件中的第一行有一个整数N,1<=n<=30 000,为城镇的数目。下面N-1行,每行由两个整数a 和b (1<=a, b<=n; a<>b)组成,表示城镇a和城镇b有公路连接。在第N+1行为一个整数M,下面的M行,每行有该商人需要顺次经过的各城镇编号。
输出描述 Output Description
在输出文件中输出该商人旅行的最短时间。
样例输入 Sample Input
5
1 2
1 5
3 5
4 5
4
1
3
2
5
样例输出 Sample Output
7
求最近公共祖先(lca)的裸题,mark一下lca的写法。
#include<iostream> #include<vector> #include<cmath> #include<cstring> #include<cstdio> #define N 100005 using namespace std; struct edge{int v,w;}; vector<edge>edges[N]; int grand[N][25]={0},gw[N][25]={0}; int depth[N],DEPTH,n; void addedge(int a,int b,int w) { edges[a].push_back((edge){b,w}); edges[b].push_back((edge){a,w}); } void dfs(int x) { for(int i=1;i<=DEPTH;i++) { grand[x][i]=grand[grand[x][i-1]][i-1]; gw[x][i]=gw[x][i-1]+gw[grand[x][i-1]][i-1]; } for(int i=0;i<edges[x].size();i++) { int to=edges[x][i].v; if(grand[x][0]==to)continue; depth[to]=depth[x]+1; grand[to][0]=x; gw[to][0]=edges[x][i].w; dfs(to); } } void init() { DEPTH=floor(log(n + 0.0) / log(2.0)); depth[1]=1; memset(grand,0,sizeof(grand)); memset(gw,0,sizeof(gw)); dfs(1); } int lca(int a,int b) { if(depth[a]>depth[b])swap(a,b); int ans=0; for(int i=DEPTH;i>=0;i--) if(depth[a]<depth[b]&&depth[grand[b][i]]>=depth[a]) ans+=gw[b][i],b=grand[b][i]; for(int i=DEPTH;i>=0;i--) if(grand[a][i]!=grand[b][i]) { ans+=gw[a][i]; ans+=gw[b][i]; a=grand[a][i]; b=grand[b][i]; } if(a!=b) { ans+=gw[a][0]; ans+=gw[b][0]; } return ans; } int main() { int a,b; scanf("%d",&n); for(int i=0;i<n-1;i++) { scanf("%d %d",&a,&b); addedge(a,b,1); } init(); int ans=0; int m,last=1; scanf("%d",&m); while(m--) { scanf("%d",&a); ans+=lca(last,a); last=a; } printf("%d",ans); return 0; }