/*
*算法引入:
*树上两点的最近公共祖先;
*对于有根树的两个结点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. C语言中的符号重载

    摘自<C专家编程>第二章37页                     C语言中符号的重载 符号 意义 static 在函数内部,表示该变量的值在各个调用间一直保持延续性在函数这一级,表示 ...

  2. C++课后习题

    一.设计一个类people,有保护数据成员:age(年龄,整型),name(姓名,string),行为成员:两个构造函数(一个默认,另一个带参数):析构函数:void setValue(int m, ...

  3. 做一个U盘的学习路线

    最近想研究一个U盘,然后顺便熟悉一下USB协议.因为USB协议比较复杂, 常用的复杂外设除了WiFi,Ethernet,SDIO和USB这些就是USB了,学习USB的时候肯定要拿一个东西下手,所以简单 ...

  4. PHP7兼容mysql_connect的方法

    在php7版本的时候,mysql_connect已经不再被支持了,本文将讲述在代码层面实现php7兼容mysql系列,mysql_connect等操作. PHP7不再兼容mysql系列函数,入mysq ...

  5. 剑指offer计划25(模拟中等)---java

    1.1.题目1 剑指 Offer 29. 顺时针打印矩阵 1.2.解法 常规开头,先判断特殊情况,然后创建四个变量存放矩阵四边的长度限制. 创建res数组存放结果. 循坏开始,遍历完一行或者一列,就将 ...

  6. go 成长路上的坑(2)

    请看代码 代码一 package main import "fmt" func main() { var a Integer = 1 var b Integer = 2 var i ...

  7. UOJ#454-[UER #8]打雪仗【通信题】

    正题 题目链接:https://uoj.ac/problem/454 题目大意 \(Alice\)有一个长度为\(2n\)的\(01\)串,\(Bob\)有\(n\)个在\([1,2n]\)位置的下标 ...

  8. CF1392G-Omkar and Pies【dp】

    正题 题目链接:https://www.luogu.com.cn/problem/CF1392G 题目大意 两个长度为\(k\)的起始和目标01串. \(n\)个操作交换起始串的两个位置,选择一段长度 ...

  9. Windows下CMake编译安装OpenCV

    Windows下CMake编译安装OpenCV 这是一个面向新手的在windows上运进opencv, helloword的教程. 在这里我们使用vs2019来编译opencv, 并运行一个hello ...

  10. 数据库语法整理及WAF绕过方式

    关系型数据库 关系型数据库:指采用了关系模型来组织数据的数据库. 直白的说就是:关系型数据库最典型的数据结构是表,由二维表及其之间的联系所组成的一个数据组织 当今主流的关系型数据库有:Oracle,M ...