Tanjar+并查集(离线查询)
参考博客:https://www.cnblogs.com/jsawz/p/6723221.html
#include<cstdio>
#define N 420000
struct hehe{
int next;
int to;
int lca;
};
hehe edge[N];//树的链表
hehe qedge[N];//需要查询LCA的两节点的链表
int n,m,p,x,y;
int num_edge,num_qedge,head[N],qhead[N];
int father[N];
int visit[N];//判断是否被找过
void add_edge(int from,int to){//建立树的链表
edge[++num_edge].next=head[from];
edge[num_edge].to=to;
head[from]=num_edge;
}
void add_qedge(int from,int to){//建立需要查询LCA的两节点的链表
qedge[++num_qedge].next=qhead[from];
qedge[num_qedge].to=to;
qhead[from]=num_qedge;
}
int find(int z){//找爹函数
if(father[z]!=z)
father[z]=find(father[z]);
return father[z];
}
int dfs(int x){//把整棵树的一部分看作以节点x为根节点的小树
father[x]=x;//由于节点x被看作是根节点,所以把x的father设为它自己
visit[x]=1;//标记为已被搜索过
for(int k=head[x];k;k=edge[k].next)//遍历所有与x相连的节点
if(!visit[edge[k].to]){//若未被搜索
dfs(edge[k].to);//以该节点为根节点搞小树
father[edge[k].to]=x;//把x的孩子节点的father重新设为x
}
for(int k=qhead[x];k;k=qedge[k].next)//搜索包含节点x的所有询问
if(visit[qedge[k].to]){//如果另一节点已被搜索过
qedge[k].lca=find(qedge[k].to);//把另一节点的祖先设为这两个节点的最近公共祖先
if(k%2)//由于将每一组查询变为两组,所以2n-1和2n的结果是一样的
qedge[k+1].lca=qedge[k].lca;
else
qedge[k-1].lca=qedge[k].lca;
}
}
int main(){
scanf("%d%d%d",&n,&m,&p);//输入节点数,查询数和根节点
for(int i=1;i<n;++i){
scanf("%d%d",&x,&y);//输入每条边
add_edge(x,y);
add_edge(y,x);
}
for(int i=1;i<=m;++i){
scanf("%d%d",&x,&y);//输入每次查询,考虑(u,v)时若查找到u但v未被查找,所以将(u,v)(v,u)全部记录
add_qedge(x,y);
add_qedge(y,x);
}
dfs(p);//进入以p为根节点的树的深搜
for(int i=1;i<=m;i++)
printf("%d ",qedge[i*2].lca);//两者结果一样,只输出一组即可
return 0;
}
倍增LCA(在线查询)
///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const ll mod=1e12;
const int INF=0x3f3f3f3f;
int t,n,q;
struct node
{
int e;
int c;
int p;
}load[80000];
int head[40005],sign;
void add_edge(int s,int e,int c)
{
load[++sign]=node{e,c,head[s]};
head[s]=sign;
}
int grand[40005][18];
int depth[40005];
int dis[40005];
int N;
void dfs(int s,int pre)
{
for(int i=1;i<=N;i++)
grand[s][i]=grand[grand[s][i-1]][i-1];
for(int i=head[s];i!=-1;i=load[i].p)
{
int e=load[i].e;
int c=load[i].c;
if(e!=pre)
{
depth[e]=depth[s]+1;
grand[e][0]=s;
dis[e]=dis[s]+c;
dfs(e,s);
}
}
}
void init()
{
N=log2(n);
memset(grand,0,sizeof(grand));
for(int i=1;i<=n;i++)
{
head[i]=-1;
dis[i]=0;
depth[i]=-1;
}
depth[1]=0;
sign=0;
}
int get_lca(int a,int b)
{
if(depth[a]>depth[b])
swap(a,b);
for(int i=N;i>=0;i--)
{
if(depth[b]>=depth[a]&&depth[grand[b][i]]>=depth[a])
b=grand[b][i];
}
for(int i=N;i>=0;i--)
{
if(grand[a][i]!=grand[b][i])
{
a=grand[a][i];
b=grand[b][i];
}
}
return a==b?a:grand[b][0];
}
int main()
{
int s,e,c;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&q);
init();
for(int i=1;i<n;i++)
{
scanf("%d %d %d",&s,&e,&c);
add_edge(s,e,c);
add_edge(e,s,c);
}
dfs(1,-1);
while(q--)
{
scanf("%d %d",&s,&e);
int x=get_lca(s,e);
printf("%d\n",dis[s]+dis[e]-2*dis[x]);
}
}
return 0;
}