LCA的 Trajan 算法
标签:end sof i++ ios stream 初始 art ble iostream
参考博客
参考博客
根据博客的模拟,就可以知道做法和思想。
现在就是实现他。
例题 :hdu 2586
题意:m 个询问,x 到 y 的距离,我们的思想就是求出:x到根的距离+y到根的距离-2*(lca[ x ,y ])到跟的距离。
代码:
#include
#include
#include
#includestring.h>
using namespace std;
const int max_edge=100005;//边数
const int max_Q=405;//问题
const int max_=40005;//节点
struct Tree{//树-邻接表
int to;
int v;
int next;
};
struct Question{//离线-问题
int to;
int id;
int next;
};
struct Tree a[max_edge];//树数组
struct Question b[max_];//问题数组
int N,M;
int edge[max_];//边记录next
int tot1,tot2;
bool vis[max_];//标记数组
int st[max_Q],ed[max_Q];//问题的x和y
int question[max_];//问题-记录next
int fa[max_];//父节点
int dis[max_];//到根的距离
int LCA[max_Q];//问题的LCA
void add_edge(int x,int y,int v)//建树
{
a[++tot1].to=y;
a[tot1].v=v;
a[tot1].next=edge[x];
edge[x]=tot1;
}
void add_question(int x,int y,int id)//离线
{
b[++tot2].to=y;
b[tot2].id=id;
b[tot2].next=question[x];
question[x]=tot2;
}
int find_fa(int x)//寻找父节点
{
if(fa[x]==x)
return x;
return fa[x]=find_fa(fa[x]);
}
void Tarjan(int x)
{
fa[x]=x;//作为当前的根节点,将其父亲指向自己
vis[x]=1;//标记
for(int i=question[x];i;i=b[i].next)//寻找问题中与自己有关节点
{
int go_to=b[i].to;
if(vis[go_to]==true)//如果有关节点走过,记录LCA
LCA[b[i].id]=find_fa(go_to);
}
for(int i=edge[x];i;i=a[i].next)//沿边遍历
{
int go_to=a[i].to;
if(vis[go_to]==false)
{
dis[go_to]=dis[x]+a[i].v;//更新距离
Tarjan(go_to);//递归遍历
fa[go_to]=x;//归并父节点
}
}
}
int main()
{
int T;
cin>>T;//测试组数
while(T--)
{
memset(vis,0,sizeof(vis));
memset(question,0,sizeof(question));
memset(edge,0,sizeof(edge));
memset(dis,0,sizeof(dis));
memset(LCA,0,sizeof(LCA));
tot1=0,tot2=0;//初始归零
cin>>N>>M;
for(int i=0;i1;i++)
{
int x,y,v;
cin>>x>>y>>v;
add_edge(x,y,v);//双向建边
add_edge(y,x,v);
}
for(int i=0;i)
{
int x,y;
cin>>x>>y;
add_question(x,y,i);
add_question(y,x,i);//保证找有关点时不漏
st[i]=x,ed[i]=y;//记录问题的x,y
}
Tarjan(1);
for(int i=0;i)
{
int temp=dis[st[i]]+dis[ed[i]]-(2*dis[LCA[i]]);//结果
coutendl;
}
}
}
LCA的 Trajan 算法
标签:end sof i++ ios stream 初始 art ble iostream
原文地址:https://www.cnblogs.com/linhaitai/p/9736115.html
评论