题意:求出两个树节点的距离
思路:可以转化成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;
}