1602: [Usaco2008 Oct]牧场行走
Time Limit: 5 Sec Memory Limit: 64 MB
Submit: 379 Solved: 216
[Submit][Status][Discuss]
Description
N头牛(2<=n<=1000)别人被标记为1到n,在同样被标记1到n的n块土地上吃草,第i头牛在第i块牧场吃草。
这n块土地被n-1条边连接。
奶牛可以在边上行走,第i条边连接第Ai,Bi块牧场,第i条边的长度是Li(1<=Li<=10000)。
这些边被安排成任意两头奶牛都可以通过这些边到达的情况,所以说这是一棵树。
这些奶牛是非常喜欢交际的,经常会去互相访问,他们想让你去帮助他们计算Q(1<=q<=1000)对奶牛之间的距离。
Input
*第一行:两个被空格隔开的整数:N和Q
*第二行到第n行:第i+1行有两个被空格隔开的整数:AI,BI,LI
*第n+1行到n+Q行:每一行有两个空格隔开的整数:P1,P2,表示两头奶牛的编号。
Output
*第1行到第Q行:每行输出一个数,表示那两头奶牛之间的距离。
Sample Input
4 2
2 1 2
4 3 2
1 4 3
1 2
3 2
Sample Output
2
7
HINT
Source
【代码】
//O(qlogn)
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<vector> 5 #include<iostream> 6 #define FOR(a,b,c) for(int a=(b);a<(c);a++) 7 using namespace std; 8 9 const int maxn = 100000+10; 10 const int maxd = 22; 11 12 struct Edge{ int u,v,w; 13 }; 14 vector<int> G[maxn]; 15 vector<Edge> es; 16 17 int d[maxn],dist[maxn]; 18 int p[maxn][maxd],pd[maxn][maxd]; 19 20 void addedge(int u,int v,int w) { 21 es.push_back((Edge){u,v,w}); 22 int m=es.size(); G[u].push_back(m-1); 23 } 24 void dfs(int u,int fa) { //构造dist 25 for(int i=0;i<G[u].size();i++) { 26 Edge e=es[G[u][i]]; 27 int v=e.v; 28 if(v!=fa) { 29 d[v]=d[u]+1; dist[v]=dist[u]+e.w; 30 p[v][0]=u , pd[v][0]=e.w; 31 dfs(v,u); 32 } 33 } 34 } 35 int query(int u,int v) { //查询 36 if(d[v]>d[u]) swap(u,v); 37 for(int i=maxd-1;i>=0;i--) 38 if(d[p[u][i]]>=d[v]) u=p[u][i]; //调整至同意高度 39 if(u==v) return u; //同一子树则返回 40 for(int i=maxd-1;i>=0;i--) 41 if(p[u][i]!=p[v][i]) 42 u=p[u][i] , v=p[v][i]; //查找lca 43 return p[u][0]; 44 } 45 46 int n,q; 47 48 void read(int& x) { 49 char c=getchar(); 50 while(!isdigit(c)) c=getchar(); 51 x=0; 52 while(isdigit(c)) 53 x=x*10+c-‘0‘ , c=getchar(); 54 } 55 int main() { 56 read(n),read(q); 57 int u,v,w; 58 for(int i=1;i<n;i++) { 59 read(u),read(v),read(w); 60 addedge(u,v,w) , addedge(v,u,w); 61 } 62 dfs(1,-1); 63 for(int k=1;k<maxd;k++) for(int i=1;i<=n;i++) { //构造倍增数组 64 p[i][k]=p[p[i][k-1]][k-1]; 65 pd[i][k]=pd[i][k-1]+pd[p[i][k-1]][k-1]; 66 } 67 while(q--) { 68 read(u),read(v); 69 printf("%d\n",dist[u]+dist[v]-2*dist[query(u,v)]); 70 } 71 return 0; 72 }
beizeng
//O(n+q)
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<vector> 5 #include<iostream> 6 using namespace std; 7 8 const int maxn = 100000+10; 9 const int maxq = 100000+10; 10 11 struct Edge{ int u,v,w; 12 }; 13 struct node { int v,i; }; 14 vector<int> G[maxn]; 15 vector<Edge> es; 16 vector<node> que[maxn]; 17 int U[maxq],V[maxq]; 18 19 void addedge(int u,int v,int w) { 20 es.push_back((Edge){u,v,w}); 21 int m=es.size(); G[u].push_back(m-1); 22 } 23 int p[maxn]; 24 int find(int u) { return u==p[u]? u:p[u]=find(p[u]); 25 } 26 27 int dist[maxn]; 28 void dfs(int u,int fa) { //求dist 29 for(int i=0;i<G[u].size();i++) { 30 Edge e=es[G[u][i]]; int v=e.v; 31 if(v!=fa) dist[v]=dist[u]+e.w , dfs(v,u); 32 } 33 } 34 int vis[maxn],lca[maxq]; 35 void tarjan(int u,int fa) { 36 p[u]=u; 37 for(int i=0;i<G[u].size();i++) { 38 Edge e=es[G[u][i]]; int v=e.v; 39 if(v!=fa) tarjan(v,u),p[v]=u; //递归处理 合并集合 40 } 41 vis[u]=1; 42 for(int i=0;i<que[u].size();i++) { //求与u相关的询问 43 int v=que[u][i].v; 44 if(vis[v]) lca[que[u][i].i]=find(v); 45 //如果已经被访问 lca为v集合的代表元x //若v是u子则x=u 若非子则因u还未访问完集合并未向上合并所以代表元为lca 46 } 47 } 48 49 int n,q; 50 void read(int& x) { 51 char c=getchar(); 52 while(!isdigit(c)) c=getchar(); 53 x=0; 54 while(isdigit(c)) 55 x=x*10+c-‘0‘ , c=getchar(); 56 } 57 58 int main() { 59 read(n),read(q); 60 int u,v,w; 61 for(int i=1;i<n;i++) { 62 read(u),read(v),read(w); 63 addedge(u,v,w) , addedge(v,u,w); 64 } 65 for(int i=0;i<q;i++) { 66 read(u),read(v); 67 U[i]=u , V[i]=v; 68 que[u].push_back((node){v,i}); 69 que[v].push_back((node){u,i}); 70 } 71 tarjan(n>>1,-1) , dfs(n>>1,-1); 72 for(int i=0;i<q;i++) { 73 u=U[i] , v=V[i]; 74 int lc=lca[i]; 75 printf("%d\n",dist[u]+dist[v]-(dist[lc]<<1)); 76 } 77 return 0; 78 }
tarjan
时间: 2024-11-17 06:24:48