题意:求出两个树节点的距离
思路:可以转化成d[u]+d[v]-2*d[lca(u,v)] d[i]代表根节点到i的距离 lca(u,v)就是u,v的最近公共祖先的意思
模板题
参考
参考
第一种是tarjan的,比较快
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cmath> using namespace std; const int N = 40005; const int M = 20010; int n, m, k, tot, ks; int first[N], R[N<<1], head[N], dir[N<<1], vec[N<<1], _first[N], fa[N]; int dp[N<<1][25]; bool vis[N]; struct edge{ int v, w, nex; }e[N<<1]; struct ques{ int v,lca,nex; }eq[M]; void init(){ memset(first, -1, sizeof(first)); memset(vis,false,sizeof(vis)); memset(_first, -1, sizeof(_first)); dir[1] = tot = k = ks = 0; } inline void addedge(int x, int y, int z){ e[k].v = y, e[k].w = z, e[k].nex = first[x]; first[x] = k++; e[k].v = x, e[k].w = z, e[k].nex = first[y]; first[y] = k++; } inline void addque(int x, int y){ eq[ks].v = y, eq[ks].lca = -1, eq[ks].nex = _first[x]; _first[x] = ks++; eq[ks].v = x, eq[ks].lca = -1, eq[ks].nex = _first[y]; _first[y] = ks++; } int find(int x){ return x == fa[x]? x : fa[x] = find(fa[x]); } void tarjan(int u){ vis[u] = true; fa[u] = u; for(int i = first[u]; ~i; i = e[i].nex){ int v = e[i].v, w = e[i].w; if(!vis[v]){ dir[v] = dir[u] + w; tarjan(v); fa[v] = u; } } for(int i = _first[u]; ~i; i = eq[i].nex){ int v = eq[i].v; if(vis[v]){ eq[i].lca = eq[i^1].lca = find(eq[i].v); } } } int main(){ int x,y,z; char temp[5]; while(~scanf("%d%d", &n, &m)){ init(); for(int i = 0; i < m; i++){ scanf("%d%d%d %s", &x, &y, &z, temp); addedge(x,y,z); } int q; scanf("%d",&q); for(int i = 0; i < q; i++){ int u,v; scanf("%d%d",&u,&v); addque(u,v); } tarjan(1); for(int i = 0; i < q; i++){ int s = i*2 , u =eq[s].v, v = eq[s+1].v, lca = eq[s].lca; printf("%d\n",dir[u] + dir[v] - 2*dir[lca]); } } return 0; }
第二种是RMQ的思想
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cmath> using namespace std; const int N = 40005; const int M = 25; int n, m, k, tot; int first[N], R[N<<1], head[N], dir[N<<1], vec[N<<1]; int dp[N<<1][25]; bool vis[N]; struct edge{ int v, w, nex; }e[N<<1]; inline void addedge(int x, int y, int z){ e[k].v = y, e[k].w = z, e[k].nex = first[x]; first[x] = k++; e[k].v = x, e[k].w = z, e[k].nex = first[y]; first[y] = k++; } void init(){ memset(first, -1, sizeof(first)); memset(vis,false,sizeof(vis)); dir[1] = tot = k = 0; } void dfs(int u, int dep){ vis[u] = true, head[u] = ++tot, vec[tot] = u,R[tot] = dep; for(int i = first[u]; ~i; i = e[i].nex){ int v = e[i].v, w = e[i].w; if(!vis[v]){ dir[v] = dir[u] + w; dfs(v,dep+1); vec[++tot] = u,R[tot] = dep; } } } void ST(int len){ int p = (int) (log((double)(len))/log(2.0)); for(int i = 1; i <= len; i++)dp[i][0] = i; for(int j = 1; j <= p; j++){ for(int i = 1; i+(1<<j)-1 <= len; i++){ dp[i][j] = R[dp[i][j-1]] < R[dp[i+(1<<(j-1))][j-1]]? dp[i][j-1] : dp[i+(1<<(j-1))][j-1]; } } } int rmq(int x, int y){ int p = (int)(log((double)(y-x+1))/log(2.0)); int a = dp[x][p] , b = dp[y-(1<<p)+1][p]; return R[a] < R[b] ? a:b; } int LCA(int u, int v){ int x = head[u], y = head[v]; if(x > y)swap(x,y); return vec[rmq(x,y)]; } int main(){ int x,y,z; char temp[5]; while(~scanf("%d%d", &n, &m)){ init(); for(int i = 0; i < m; i++){ scanf("%d%d%d %s", &x, &y, &z, temp); addedge(x,y,z); } dfs(1,1); ST(tot); int q; scanf("%d",&q); while(q--){ int u,v,lca; scanf("%d%d",&u,&v); lca = LCA(u,v); printf("%d\n",dir[u] + dir[v] - 2*dir[lca]); } } return 0; }
第三种是倍增的方法
参考
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cmath> using namespace std; const int N = 50005; const int M = 50; int n, m, k, tot; int first[N], dep[N], dir[N], fa[N][M]; bool vis[N]; struct edge{ int v, w, nex; }e[N<<1]; inline void addedge(int x, int y, int z){ e[k].v = y, e[k].w = z, e[k].nex = first[x]; first[x] = k++; e[k].v = x, e[k].w = z, e[k].nex = first[y]; first[y] = k++; } void init(){ memset(first, -1, sizeof(first)); memset(vis, false, sizeof(vis)); memset(fa, -1, sizeof(fa)); dir[1] = tot = k = 0; } void dfs(int u, int d){ vis[u] = true,dep[u] = d; for(int i = first[u]; ~i; i = e[i].nex){ int v = e[i].v, w = e[i].w; if(!vis[v]){ dir[v] = dir[u] + w; fa[v][0] = u; dfs(v,d+1); } } } void init_fa(){ for(int j = 1; (1<<j) <= n; j++){ for(int i = 1; i <= n; i++){ fa[i][j] = fa[fa[i][j-1]][j-1]; } } } int LCA(int a, int b){ int i, j; if(dep[a] < dep[b])swap(a, b); for(i = 0; (1<<i) <= dep[a]; i++);i--; for( j = i; j >= 0; j--){ if(dep[a] - (1<<j) >= dep[b]) a = fa[a][j]; } if(a == b)return a; for(int j = i; j >= 0; j--){ if(fa[a][j] != -1 && fa[a][j] != fa[b][j]){ a = fa[a][j], b = fa[b][j]; } } return fa[a][0]; } int main(){ int x,y,z; char temp[5]; while(~scanf("%d%d", &n, &m)){ init(); for(int i = 0; i < m; i++){ scanf("%d%d%d %s", &x, &y, &z, temp); addedge(x,y,z); } dfs(1,0); init_fa(); int q; scanf("%d",&q); while(q--){ int u,v,lca; scanf("%d%d",&u,&v); lca = LCA(u,v); printf("%d\n",dir[u] + dir[v] - 2*dir[lca]); } } return 0; }