可用倍增LCA解题
http://codevs.cn/problem/2370/
#include<bits/stdc++.h> using namespace std; const int M=5e4+5; const int N=20; struct node{ int v,w; node(int vv=0,int ww=0):v(vv),w(ww){} }; vector<node>e[M]; int n,grand[M][N],dis[M][N],deep[M],book[M],root,s; void dfs(int u){ for(int i=1;i<=s;i++){ grand[u][i]=grand[grand[u][i-1]][i-1]; dis[u][i]=dis[u][i-1]+dis[grand[u][i-1]][i-1]; if(!grand[u][i]) break; } for(int i=0;i<e[u].size();i++){ int v=e[u][i].v; if(v!=grand[u][0]){ grand[v][0]=u; deep[v]=deep[u]+1; dis[v][0]=e[u][i].w; dfs(v); } } } void init(){ s=floor(log(1.0*n)/log(2.0)); deep[0]=-1; dfs(root); } int LCA(int a,int b){ if(deep[a]>deep[b]) swap(a,b); int ans=0; for(int i=s;i>=0;i--){ if(deep[a]<deep[b]&&deep[a]<=deep[grand[b][i]]) ans+=dis[b][i],b=grand[b][i]; } for(int i=s;i>=0;i--){ if(grand[a][i]!=grand[b][i]) ans+=dis[a][i],ans+=dis[b][i],a=grand[a][i],b=grand[b][i]; } if(a!=b) ans+=dis[a][0]+dis[b][0]; return ans; } int main(){ scanf("%d",&n); for(int i=1;i<n;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); u++; v++;///fu book[u]=1; e[u].push_back(node(v,w)); e[v].push_back(node(u,w)); } for(int i=1;i<=n;i++){ if(!book[i]){ root=i; break; } } init(); int m; scanf("%d",&m); while(m--){ int u,v; scanf("%d%d",&u,&v); u++,v++; printf("%d\n",LCA(u,v)); } return 0; }
http://codevs.cn/problem/1036/
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<cmath> using namespace std; const int M=3e4+4; const int N=20; struct node{ int v,w; node(int vv=0,int ww=0):v(vv),w(ww){} }; vector<node>e[M]; int s,grand[M][N],dis[M][N],book[M],deep[M],root,n; void dfs(int u){ for(int i=1;i<=s;i++){ grand[u][i]=grand[grand[u][i-1]][i-1]; dis[u][i]=dis[u][i-1]+dis[grand[u][i-1]][i-1]; if(!grand[u][i]) break; } for(int i=0;i<e[u].size();i++){ int v=e[u][i].v; if(v!=grand[u][0]){ grand[v][0]=u; deep[v]=deep[u]+1; dis[v][0]=e[u][i].w; dfs(v); } // cout<<"!!"<<endl; } } void init(){ s=floor(log(1.0*n)/log(2.0)); deep[0]=-1; dfs(root); } int LCA(int a,int b){ if(deep[a]>deep[b]) swap(a,b); int ans=0; for(int i=s;i>=0;i--){ if(deep[b]>deep[a]&&deep[a]<=deep[grand[b][i]]) ans+=dis[b][i],b=grand[b][i]; } for(int i=s;i>=0;i--) if(grand[a][i]!=grand[b][i]) ans+=dis[a][i]+dis[b][i],b=grand[b][i],a=grand[a][i]; if(a!=b) ans+=dis[a][0]+dis[b][0]; return ans; } int main(){ scanf("%d",&n); for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); book[v]=1; e[u].push_back(node(v,1)); e[v].push_back(node(u,1)); } for(int i=1;i<=n;i++) if(!book[i]){ root=i; break; } init(); int m,u,v; scanf("%d",&m); scanf("%d",&u); int ans=0; for(int i=1;i<m;i++){ scanf("%d",&v); ans+=LCA(u,v); u=v; } printf("%d\n",ans); return 0; }
http://oj.fjaxyz.com:3389/problem.php?id=223
当LCA(a,b)==a时才能参赛
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<cmath> using namespace std; typedef long long ll; const int M=1e4+4; struct node{ int v; ll w; node(int vv=0,ll ww=0):v(vv),w(ww){} }; vector<node>e[M]; int grand[M][20],s,n,root,deep[M]; ll dis[M][20],num,numt; void dfs(int u){ for(int i=1;i<=s;i++){ grand[u][i]=grand[grand[u][i-1]][i-1]; dis[u][i]=dis[u][i-1]+dis[grand[u][i-1]][i-1]; if(!grand[u][i]) break; } for(int i=0;i<e[u].size();i++){ int v=e[u][i].v; if(v!=grand[u][0]){ grand[v][0]=u; deep[v]=deep[u]+1; dis[v][0]=e[u][i].w; dfs(v); } } } void init(){ s=floor(log(1.0*n)/log(2.0)); deep[0]=-1; dfs(root); } void LCA(int u,int v){ int a=u,b=v; if(deep[a]>deep[b]) swap(a,b) ; ll ans=0; for(int i=s;i>=0;i--){ if(deep[b]>deep[a]&&deep[a]<=deep[grand[b][i]]) ans+=dis[b][i],b=grand[b][i]; } for(int i=s;i>=0;i--){ if(grand[b][i]!=grand[a][i]) ans+=dis[b][i]+dis[a][i],a=grand[a][i],b=grand[b][i]; } if(a!=b) ans+=dis[a][0]+dis[b][0],a=grand[a][0],b=grand[b][0]; if(a!=u) return ; // cout<<"!!"<<endl; numt+=ans; num++; } int main(){ int m; scanf("%d%d",&n,&m); for(int i=1;i<n;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); e[u].push_back(node(v,w)); e[v].push_back(node(u,w)); } root=1; init(); while(m--){ int u,v; scanf("%d%d",&u,&v); LCA(u,v); } printf("%d\n",num); printf("%d\n",numt); return 0; }
zoj 3198
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3320
吐槽一下输出格式,言不表意!!
题意:求用最小权值的路径连接起3个节点,问这些路径的和;
分析,答案就是俩俩之间路径和/2;
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<cmath> using namespace std; const int M=5e4+4; struct node{ int v,w; node(int vv,int ww):v(vv),w(ww){} }; vector<node>e[M]; int grand[M][20],dis[M][20],deep[M],root,s,n,book[M]; void dfs(int u){ for(int i=1;i<=s;i++){ grand[u][i]=grand[grand[u][i-1]][i-1]; dis[u][i]=dis[grand[u][i-1]][i-1]+dis[u][i-1]; if(!grand[u][i]) break; } for(int i=0;i<e[u].size();i++){ int v=e[u][i].v; if(v!=grand[u][0]){ grand[v][0]=u; deep[v]=deep[u]+1; dis[v][0]=e[u][i].w; dfs(v); } } } void init(){ s=floor(log(1.0*n)/log(2.0)); deep[0]=-1; dfs(root); } int LCA(int a,int b){ if(deep[a]>deep[b]) swap(a,b); int ans=0; for(int i=s;i>=0;i--){ if(deep[a]<deep[b]&&deep[a]<=deep[grand[b][i]]) ans+=dis[b][i],b=grand[b][i]; } for(int i=s;i>=0;i--){ if(grand[a][i]!=grand[b][i]) ans+=dis[a][i]+dis[b][i],a=grand[a][i],b=grand[b][i]; } if(a!=b) ans+=dis[a][0]+dis[b][0]; return ans; } int main(){ int flag=1; while(~scanf("%d",&n)&&n){ if(flag) flag=0; else printf("\n"); for(int i=0;i<=n;i++){ e[i].clear(); deep[i]=0; book[i]=0; for(int j=0;j<=16;j++) grand[i][j]=dis[i][j]=0; } for(int i=1;i<n;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); u++; v++; book[v]=1; e[u].push_back(node(v,w)); e[v].push_back(node(u,w)); } for(int i=1;i<=n;i++){ if(!book[i]){ root=i; break; } } init(); int m; scanf("%d",&m); while(m--){ int u,v,k; scanf("%d%d%d",&u,&v,&k); u++,v++,k++; int ans=0; ans+=LCA(u,v); // cout<<LCA(u,v)<<"~~~~~~~~1"<<endl; ans+=LCA(u,k); // cout<<LCA(u,k)<<"~~~~~~~~2"<<endl; ans+=LCA(v,k); // cout<<LCA(k,v)<<"~~~~~~~~3"<<endl; printf("%d\n",ans/2); } } return 0; }