树上倍增法
算法概况:基于动态规划,适用于多次查询
时间复杂度:O((n+m)logn)
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<cmath> using namespace std; const int SIZE=50010; int f[SIZE][20],d[SIZE],dist[SIZE]; int ver[SIZE<<1],Next[SIZE<<1],edge[SIZE<<1],head[SIZE]; int T,n,m,tot,t; queue<int> q; void add(int x,int y,int z){ ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot; } void bfs(){//初始化 q.push(1); d[1]=1; while(q.size()){ int x=q.front(); q.pop(); for(int i=head[x];i;i=Next[i]){ int y=ver[i]; if(d[y]) continue; d[y]=d[x]+1; dist[y]=dist[x]+edge[i]; f[y][0]=x; for(int j=1;j<=t;j++) f[y][j]=f[f[y][j-1]][j-1]; q.push(y); } } } int lca(int x,int y){//回答一个询问 if(d[x]>d[y]) swap(x,y); for(int i=t;i>=0;i--) if(d[f[y][i]]>=d[x]) y=f[y][i]; if(x==y) return x; for(int i=t;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } int main(){ cin>>T; while(T--){ cin>>n>>m; t=log2(n)+1; for(int i=1;i<=n;i++) head[i]=d[i]=0; tot=0; for(int i=1;i<n;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } bfs(); for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); printf("%d\n",dist[x]+dist[y]-2*dist[lca(x,y)]); } } }
LCA的tarjan算法
算法概况:使用并查集对“向上标记法”的优化
时间复杂度:O(n+m)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int N=50010; int ver[N<<1],Next[N<<1],edge[N<<1],head[N<<1]; int fa[N],d[N],v[N],lca[N],ans[N]; vector<int> query[N],query_id[N]; int T,n,m,tot,t; void add(int x,int y,int z){ ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot; } void add_query(int x,int y,int id){ query[x].push_back(y),query_id[x].push_back(id); query[y].push_back(x),query_id[y].push_back(id); } int get(int x){ if(x==fa[x]) return x; return fa[x]=get(fa[x]); } void tarjan(int x){ v[x]=1; for(int i=head[x];i;i=Next[i]){ int y=ver[i]; if(v[y]) continue; d[y]=d[x]+edge[i]; tarjan(y); fa[y]=x; } for(int i=0;i<query[x].size();i++){ int y=query[x][i],id=query_id[x][i]; if(v[y]==2){ int lca=get(y); ans[id]=min(ans[id],d[x]+d[y]-2*d[lca]); } } v[x]=2; } int main(){ cin>>T; while(T--){ cin>>n>>m; for(int i=1;i<=n;i++){ head[i]=0; fa[i]=i; v[i]=0; query[i].clear(); query_id[i].clear(); } tot=0; for(int i=1;i<n;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); if(x==y) ans[i]=0; else{ add_query(x,y,i); ans[i]=1<<30; } } tarjan(1); for(int i=1;i<=m;i++) printf("%d\n",ans[i]); } return 0; }