/*
*算法引入:
*树上两点的最近公共祖先;
*对于有根树的两个结点u,v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u,v的祖先且x的深度尽可能大;
*对于x来说,从u到v的路径一定经过点x;
*
*算法思想:
*Tarjan_LCA离线算法;
*Tarjan算法基于dfs的框架,对于新搜到的一个结点,首先创建由这个结点构成的集合,再对当前结点的每个子树进行搜索;
*每搜索完一棵子树,则可确定子树内的LCA询问都已解决,其他的LCA询问的结果必然在这个子树之外;
*这时把子树所形成的集合与当前结点的集合合并,并将当前结点设为这个集合的祖先;
*之后继续搜索下一棵子树,直到当前结点的所有子树搜完;
*
*这时把当前结点也设为已被检查过的,同时可以处理有关当前结点的LCA询问;
*如果有一个从当前结点到结点v的询问,且v已经被检查过;
*则由于进行的是dfs,当前结点与v的最近公共祖先一定还没有被检查;
*而这个最近公共祖先的包含v的子树一定已经搜索过了,那么这个最近公共祖先一定是v所在集合的祖先;
*
*算法步骤:
*对于每一个结点:
*(1)建立以u为代表元素的集合;
*(2)遍历与u相连的结点v,如果没有被访问过,对于v使用Tarjan_LCA算法,结束后将v的集合并入u的集合;
*(3)对于与u有关的询问(u,v),如果v被访问过,则结果就是v所在集合的代表元素;
*
*算法示例:
*HDU2586(How far away?)
*
*题目大意:
*求树上任两点间的距离;
*
*算法思想:
*先dfs一遍,求出到根节点的dis;
*对于某个询问,求u和v的lca,然后res[i]=d[u]+d[v]-2*d[lca(u,v)];
*
**/
struct node{
int to,w,next,lca;
}; int fa[maxn];
int head[maxn*2];
int qhead[maxm];//询问
bool vis[maxn];
ll d[maxn];
ll res[maxm]; node edge[N*2];
node qedge[M];//询问边 int n,m;
int cnt1,cnt2; int findFa(int x){
return fa[x]==x?x:fa[x]=findFa(fa[x]);
} inline void Addedge(int u,int v,int w){
edge[++cnt1].w=w, edge[cnt1].to=v, edge[cnt1].next=head[u], head[u]=cnt1;
edge[++cnt1].w=w, edge[cnt1].to=u, edge[cnt1].next=head[v], head[v]=cnt1;
} inline void Addqedge(int u,int v){
qedge[++cnt2].to=v, qedge[cnt2].next=qhead[u], qhead[u]=cnt2;
//qedge[++cnt2].to=u, qedge[cnt2].next=qhead[v], qhead[v]=cnt2;
} void dfs(int u,int fa,ll w){
d[u]=w;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(v==fa) continue;
dfs(v,u,w+edge[i].w);
}
} void Tarjan_LCA(int u){ //离线LCA算法
fa[u]=u, vis[u]=true;
for(int i=head[u];i!=-1;i=edge[i].next){
if(!vis[edge[i].to]){
Tarjan_LCA(edge[i].to);
fa[edge[i].to]=u;
}
}
for(int i=qhead[u];i!=-1;i=qedge[i].next){
if(vis[qedge[i].to]){
qedge[i].lca=findFa(qedge[i].to);
res[i]=d[u]+d[qedge[i].to]-2*d[qedge[i].lca]; //两者距离
}
}
} void solve()
{
rep(i,0,n) fa[i]=i;
mem(head,-1); mem(qhead,-1); mem(vis,false);
cnt1=cnt2=0;
int u,v,w;
rep(i,1,n-1){
scanf("%d%d%d",&u,&v,&w);
Addedge(u,v,w);
}
while(m--){
scanf("%d%d",&u,&v);
Addqedge(u,v);
}
dfs(1,-1,0);
Tarjan_LCA(1);
} int main(){
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
solve();
rep(i,1,m)
printf("%lld\n",res[i]);
}
}

LCA-离线tarjan模板的更多相关文章

  1. [POJ1330]Nearest Common Ancestors(LCA, 离线tarjan)

    题目链接:http://poj.org/problem?id=1330 题意就是求一组最近公共祖先,昨晚学了离线tarjan,今天来实现一下. 个人感觉tarjan算法是利用了dfs序和节点深度的关系 ...

  2. 近期公共祖先(LCA)——离线Tarjan算法+并查集优化

    一. 离线Tarjan算法 LCA问题(lowest common ancestors):在一个有根树T中.两个节点和 e&sig=3136f1d5fcf75709d9ac882bd8cfe0 ...

  3. LCA离线Tarjan,树上倍增入门题

    离线Tarjian,来个JVxie大佬博客最近公共祖先LCA(Tarjan算法)的思考和算法实现,还有zhouzhendong大佬的LCA算法解析-Tarjan&倍增&RMQ(其实你们 ...

  4. [HDOJ2874]Connections between cities(LCA, 离线tarjan)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2874 这题有不连通的情况,特别注意. 觉得是存query的姿势不对,用前向星存了一遍,还是T…… /* ...

  5. hdu 2586 How far away?(LCA模板题+离线tarjan算法)

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  6. LCA(最近公共祖先)——离线 Tarjan 算法

    tarjan算法的步骤是(当dfs到节点u时):1 在并查集中建立仅有u的集合,设置该集合的祖先为u1 对u的每个孩子v:   1.1 tarjan之   1.2 合并v到父节点u的集合,确保集合的祖 ...

  7. poj 1330 LCA (倍增+离线Tarjan)

    /* 先来个倍增 */ #include<iostream> #include<cstring> #include<cstdio> #define maxn 100 ...

  8. POJ 1470 Closest Common Ancestors (LCA,离线Tarjan算法)

    Closest Common Ancestors Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 13372   Accept ...

  9. Tarjan的LCA离线算法

    LCA(Least Common Ancestors)是指树结构中两个结点的最低的公共祖先.而LCA算法则是用于求两个结点的LCA.当只需要求一对结点的LCA时,我们很容易可以利用递归算法在O(n)的 ...

  10. luogu3379 【模板】最近公共祖先(LCA) Tarjan

    LCA的Tarjan算法是一个离线算法,复杂度$O(n+q)$. 我们知道Dfs搜索树时会形成一个搜索栈.搜索栈顶节点cur时,对于另外一个节点v,它们的LCA便是v到根节点的路径与搜索栈开始分叉的那 ...

随机推荐

  1. 论文解读(SimCLR)《A Simple Framework for Contrastive Learning of Visual Representations》

    1 题目 <A Simple Framework for Contrastive Learning of Visual Representations> 作者: Ting Chen, Si ...

  2. PHP设计模式之模板方法模式

    模板方法模式,也是我们经常会在不经意间有会用到的模式之一.这个模式是对继承的最好诠释.当子类中有重复的动作时,将他们提取出来,放在父类中进行统一的处理,这就是模板方法模式的最简单通俗的解释.就像我们平 ...

  3. Shell系列(35)- for循环语法一简介及批量解压缩脚本

    for循环语法一 for 变量 in 值1 值2 值3 - do 程序 done 例子 需求:批量解压缩 脚本: #!/bin/bash cd /root/publicls *.tar.gz > ...

  4. Mybatis中使用级联查询,一对多的查询

    一.需求描述 自己在开发一个小程序的过程中,需要做的一个查询是稍微比较复杂的查询,根据用户信息去查询用户所对应的宠物信息. 一个用户可能对应多个宠物,所以在用户和宠物信息的对应关系就是一对多的关系. ...

  5. 分布式文件系统FastDFS在CentOS7上的安装及与Springboot的整合

    1. 概述 FastDFS 是目前比较流行的分布式文件系统,可以很容易的实现横向扩展.动态扩容.灾备.高可用和负载均衡. FastDFS 的服务分为 tracker 服务 和 storage 服务,  ...

  6. javascript 高阶函数 currying & uncurrying

    * currying var currying = function(fn) { var args = []; return function() { if (arguments.length === ...

  7. linux系统运维操作规范

    1.1安装流程 1.1.1 系统如无特殊要求一律采用小化安装方式进行安装. 1.1.2 安装过程开始之前需要根据实际情况进行CPU数量.磁盘容量.内存分配.文件系统.目录结构.磁盘分区规划.磁盘管理方 ...

  8. Vue 初学

    Vue 的基本代码:      概念简介:Vue.js 是目前最火的一个前端框架,只关注视图层,主要负责MVC中的V这一层     MVC 是后端的分层开发概念:     MVVM是前端视图层的概念, ...

  9. lua常用一些功能

    lua在openresty中获取请求的请求头 local head_table = ngx.req.get_headers() 由于table类型,无法直接使用ngx.say()显示,需要转换为cjs ...

  10. 关于布隆过滤器,手写你真的知其原理吗?让我来带你手写redis布隆过滤器。

    说到布隆过滤器不得不提到,redis, redis作为现在主流的nosql数据库,备受瞩目:它的丰富的value类型,以及它的偏向计算向数据移动属性减少IO的成本问题.备受开发人员的青睐.通常我们使用 ...