LCA
Posted czsharecode
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LCA相关的知识,希望对你有一定的参考价值。
Tarjan
#include<iostream>
#include<queue>
#include<list>
#include<vector>
#include<cstring>
#include<set>
#include<stack>
#include<map>
#include<cmath>
#include<algorithm>
#include<string>
#include<stdio.h>
using namespace std;
typedef long long ll;
#define MS(x,i) memset(x,i,sizeof(x))
#define rep(i,s,e) for(int i=s; i<=e; i++)
#define sc(a) scanf("%d",&a)
#define scl(a) scanf("%lld",&a)
#define sc2(a,b) scanf("%d %d", &a, &b)
#define debug printf("debug......\n");
#define pfd(x) printf("%d\n",x)
#define pfl(x) printf("%lld\n",x)
const double eps=1e-8;
const double PI = acos(-1.0);
const int inf = 0x3f3f3f3f;
const ll INF = 0x7fffffff;
const int maxn = 4e4+10;
const int M = 2e2+10;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0 , 0};
int n,q;//n个顶点 q次询问
int lca[maxn];//lca[i]表示第i个询问的结果 祖先
int dist[maxn];//dist[i]表示i到根节点的距离
//对树建图
int head[maxn];
int cnt;
struct node{
int v,nxt,w;
}edge[maxn*2];
//对询问建图
int headq[maxn];
int cntq;
struct Node{
int u,v;//起点和终点
int nxt;//同起点的下一个询问的位置
int id;//记下是第几次询问
}query[M*2];
bool vis[maxn];//访问标志
//树加边
void addEdge(int u, int v, int w){
edge[cnt].v = v;
edge[cnt].w = w;
edge[cnt].nxt = head[u];
head[u] = cnt++;
}
//询问加边
void addQ(int u, int v, int idx){
query[cntq].u = u;
query[cntq].v = v;
query[cntq].nxt = headq[u];
query[cntq].id = idx;
headq[u] = cntq++;
}
//并查集基本操作
int fa[maxn];
void init(){
rep(i,1,n+5){
fa[i] = i;
vis[i] = 0;
head[i] = 0;
headq[i] = 0;
}
dist[1] = 0;
cnt = 1;
cntq = 1;
}
int find(int x){
if(x != fa[x]){
return fa[x] = find(fa[x]);
}
return x;
}
void merge(int x, int y){
int fx = find(x);
int fy = find(y);
if(fx != fy) fa[fy] = fx;
}
//tarjan
void tarjan(int u){
vis[u] = 1;
for(int i=head[u]; i; i=edge[i].nxt){
int v = edge[i].v;
int w = edge[i].w;
if(!vis[v]){
dist[v] = w + dist[u];//沿途求出每个结点到root的距离 root=1
tarjan(v);
merge(u , v);//v回溯,u是v的父亲
}
}
//u结束 u回溯,把与u有查询关系的能更新的都更新了
for(int i=headq[u]; i; i=query[i].nxt){
int v = query[i].v;
if(vis[v]) lca[query[i].id] = find(v);
}
}
int t;
int main(){
sc(t);
while(t--){
sc2(n,q);
init();//初始化不能忘记
int u,v,w;
rep(i,1,n-1){
sc2(u,v);
sc(w);
addEdge(u,v,w);
addEdge(v,u,w);
}
rep(i,1,q){
sc2(u,v);
addQ(u,v,i);
addQ(v,u,i);
}
tarjan(1);
//事实上可以只选出奇数或者偶数次序的询问因为 (1,2) (3,4) (5,6)...括号内是等价的
rep(i,1,cntq-1){
i++;
u = query[i].u;
v = query[i].v;
int idx = query[i].id;
pfd(dist[u]+dist[v]-2*dist[lca[idx]]);
}
}
return 0;
}
以上是关于LCA的主要内容,如果未能解决你的问题,请参考以下文章
代码源 Div1 - 105#451. Dis(倍增求LCA)