开题之前先回顾一遍链表的基本操作:
struct Node
{
int value;
Node * prev,* Next;
};
Node * head ,* tail;
void initialize(){//新建链表
head = new Node();
tail = new Node();
head -> Next = tail;
tail -> prev = head;
}
void insert(Node *p,int val){//在p节点后插入包括数据为val的节点
q = new Node();
q -> value = val;
p ->Next -> prev = q;
q -> Next = p ->Next;
p -> Next = q;
q -> prev = p;
}
void remove(Node *p){//删除p节点
p -> prev -> Next = p-> Next;
p -> Next -> prev = p ->prev;
delete p;
}
void recycle(){//链表内存回收
while(head != tail){
head = head ->Next;
delete head ->prev;
}
}
分割线--------------------------------------------------------分割线
以下是邻接链表的操作
const int maxn = 1e5+7;
int tot,edge[maxn*2],ver[maxn],next[maxn],head[maxn];
void add(int x ,int y ,int z){//加入有向边(x,y),权值为z
ver[++tot] = y,edge[tot] = z;
next[tot] = head[x], head[x] = tot;
}
void find(){
for(int i = head[x];i;i = Next[i]){
int y = ver[i] , z = edge[i];
//找到一条有向边(x,y),权值为z
}
}
分割线--------------------------------------------------------分割线
引入问题:
定义:LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。
一般的做法,先求出每个点的深度,一个点一个点往上跳,等跳到同一个点结束,这样是可行的,但是我们有更好的方法-----倍增法;
倍增法顾名思义,就是跳的步数加倍,一开始从2^i 开始跳,i >= log2(点的个数)+1,下一次的跳的步数是前一次的一半,跳到同一个位置就跳,不是一个位置就不跳,但是最后的结果要往上走一步才是LCA;
分割线--------------------------------------------------------分割线
用bfs预处理出各个点的深度;f[x][k]为x点的2^k辈祖先,有以下递推式:
f[x][k] = f[f[x][k-1]][k-1], 1<=k<=logn;
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[y];
f[y][0] = x;
for(int j= 1 ; j<=t ;j++){
f[y][j] = f[f[y][j-1]][j-1];
}
q.psuh(y);
}
}
}
int lca(int x ,int y){//处理单次查询
if(d[y] > d[x])swap(x,y);
for(int i = t;i >= 0;i--){
if(d[f[y][i]] >= d[x]) y = d[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];
}
分割线--------------------------------------------------------分割线
HDU - 2586
#include<bits/stdc++.h>
using namespace std;
const int maxn = 50010;
int f[maxn][20], d[maxn], dist[maxn];
int ver[2 * maxn], Next[maxn * 2], edge[maxn * 2], head[maxn];
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.empty()) {
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[x][i]] >= d[y])x = f[x][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 = (int)(log(n) / log(2)) + 1;
memset(head,0,sizeof(0));
memset(d,0,sizeof(0));
tot = 0;
for (int i = 1; i < n; i++) {
int x, y, z;
scanf("%d%d%dd",&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)]);
}
}
return 0;
}