</pre><p align="center" style="font-family: Simsun;font-size:14px;"><span style="font-size:24px;color:blue;">【Usaco Oct08 Gold】奶牛串门(Pasture Walking)</span></p><p align="center" style="font-family: Simsun;font-size:14px;">Time Limit:30000MS Memory Limit:65536KTotal Submit:76 Accepted:50 <span style="color:read;">Case Time Limit:3000MS</span></p><p align="left" style="font-family: Simsun;font-size:14px;"><strong><span style="font-size:24px;color:#333399;">Description</span></strong></p><p style="font-family: Simsun;font-size:14px;"><span style="font-family:Times New Roman;font-size:14px;">有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)</span></p><p align="left" style="font-family: Simsun;font-size:14px;"><strong><span style="font-size:24px;color:#333399;">Input</span></strong></p><p style="font-family: Simsun;font-size:14px;"><span style="font-family:Times New Roman;font-size:14px;">第一行,两个用空格分隔的整数:N和Q 第二行到第N行,第i+1行包含三个用空格分隔的整数Ai,Bi,Li 第N+1行到第N+Q行,每行包含两个用空格分隔的整数p1,p2</span></p><p align="left" style="font-family: Simsun;font-size:14px;"><strong><span style="font-size:24px;color:#333399;">Output</span></strong></p><p style="font-family: Simsun;font-size:14px;"><span style="font-family:Times New Roman;font-size:14px;">共Q行,每行包含每次询问的最短距离的值。</span></p><p align="left" style="font-family: Simsun;font-size:14px;"><strong><span style="font-size:24px;color:#333399;">Sample Input</span></strong></p><p style="font-family: Simsun;font-size:14px;"><span style="font-family:Times New Roman;font-size:14px;"></span></p><pre><span style="font-family:Times New Roman;font-size:14px;">4 2
2 1 2
4 3 2
1 4 3
1 2
3 2</span>
Sample Output
2#include<cstdio> #include<iostream> #include<cmath> #include<cstdlib> #define maxn 1005 using namespace std; int fa[maxn][15],dep[maxn],g[maxn][maxn]; int n,m,next[maxn],last[maxn],end[maxn]; void dfs(int x) { int i,t,k; dep[x]=dep[fa[x][0]]+1; k=ceil(log(dep[x])/log(2)); for(i=1;i<=k;i++) { fa[x][i]=fa[fa[x][i-1]][i-1]; g[x][i]=g[x][i-1]+g[fa[x][i-1]][i-1]; // printf("_%d_\n",g[x][i]); } // t=last[x]; while(t) { dfs(end[t]); t=next[t]; } return; } int LCA(int x,int y) { int i,s,k,dis=0; s=ceil(log(n)/log(2)); if(dep[x]<dep[y])swap(x,y); k=dep[x]-dep[y]; for(i=0;i<=s;i++) if(k&(1<<i))dis+=g[x][i],x=fa[x][i]; // printf("--%d--\n",dis); if(x==y)return dis; s=ceil(log(dep[x])/log(2)); for(i=s;i>=0;i--) if(fa[x][i]!=fa[y][i]) { dis+=g[x][i];x=fa[x][i]; dis+=g[y][i];y=fa[y][i]; } return dis+=g[x][0]+g[y][0]; } int main() { int i,j,x,y,z; scanf("%d%d",&n,&m); for(i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&z); g[x][0]=z; fa[x][0]=y; end[i]=x;next[i]=last[y];last[y]=i;//反过来写!!!; //ps:dfs()往下搜,g[][]向上找; //这题还可以开双边,随便找一点做源点建树; } for(i=1;i<=n;i++) if(!fa[i][0]){dfs(i);break;} for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); printf("%d\n",LCA(x,y)); } return 0; }
7
Hint
样例解释:
询问1:1->2 总代价为2
询问2:3->4->1->2 总代价为7
Source
Usaco October 2008 Gold
——————直接代码——————