LCA离线算法Tarjan的模板
hdu 2586:题意:输入n个点的n-1条边的树,m组询问任意点 a b之间的最短距离
思路:LCA中的Tarjan算法,RMQ还不会。。
#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
const int N = ;
const int M = ; int head[N]; //树边邻接表的表头
int __head[N]; //保存询问的邻接表的表头
struct edge{ //保存边
int u,v,w,next;
}e[*N];
struct ask{ //保存询问
int u,v,lca,next;
}ea[M];
int dir[N]; //保存点到树根的距离
int fa[N]; //并查集,保存集合的代表元素
int ance[N]; //保存集合的组合,注意对象是集合而不是元素
bool vis[N]; //遍历时的标记数组 inline void add_edge(int u,int v,int w,int &k) //保存边
{
e[k].u = u; e[k].v = v; e[k].w = w;
e[k].next = head[u]; head[u] = k++;
u = u^v; v = u^v; u = u^v;
e[k].u = u; e[k].v = v; e[k].w = w;
e[k].next = head[u]; head[u] = k++;
} inline void add_ask(int u ,int v ,int &k) //保存询问
{
ea[k].u = u; ea[k].v = v; ea[k].lca = -;
ea[k].next = __head[u]; __head[u] = k++;
u = u^v; v = u^v; u = u^v; ///看上去深奥。。其实就是swap(u,v);
ea[k].u = u; ea[k].v = v; ea[k].lca = -;
ea[k].next = __head[u]; __head[u] = k++;
} int Find(int x)
{
return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
void Union(int u ,int v)
{
fa[v] = fa[u]; //可写为 fa[Find(v)] = fa[u];
} void Tarjan(int u)
{
vis[u] = true;
ance[u] = fa[u] = u; //可写为 ance[Find(u)] = fa[u] = u;
for(int k=head[u]; k!=-; k=e[k].next)
if( !vis[e[k].v] )
{
int v = e[k].v , w = e[k].w;
dir[v] = dir[u] + w;
Tarjan(v);
Union(u,v);
ance[Find(u)] = u;
}
for(int k=__head[u]; k!=-; k=ea[k].next)
if( vis[ea[k].v] )
{
int v = ea[k].v;
ea[k].lca = ea[k^].lca = ance[Find(v)];
}
} int main()
{
int tcase;
scanf("%d",&tcase);
while(tcase--){
int n,q;
scanf("%d%d",&n,&q);
memset(head,-,sizeof(head));
memset(__head,-,sizeof(__head));
int tot = ;
for(int i=; i<n; i++) //建树
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w,tot);
}
tot = ;
for(int i=; i<q; i++) //拆开保存询问
{
int u,v;
scanf("%d%d",&u,&v);
add_ask(u,v,tot);
}
memset(vis,,sizeof(vis));
dir[] = ;
Tarjan();
for(int i=; i<q; i++)
{
int s = i * , u = ea[s].u , v = ea[s].v , lca = ea[s].lca;
printf("%d\n",dir[u]+dir[v]-*dir[lca]);
}
} return ;
}
hdu 2874:和上题一样都是求两点之间的最短距离,但是有多棵树,所以存在不连通的情况(用father判断一下就OK),,然后华丽丽的 超内存,拿别人的代码也是MLE
#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
const int N = ;
const int M = ; int head[N];
int __head[N];
struct edge{
int u,v,w,next;
}e[*N];
struct ask{
int u,v,lca,next;
}ea[*M];
int dir[N];
int fa[N];
int ance[N];
bool vis[N]; inline void add_edge(int u,int v,int w,int &k) //保存边
{
e[k].u = u; e[k].v = v; e[k].w = w;
e[k].next = head[u]; head[u] = k++;
u = u^v; v = u^v; u = u^v;
e[k].u = u; e[k].v = v; e[k].w = w;
e[k].next = head[u]; head[u] = k++;
} inline void add_ask(int u ,int v ,int &k) //保存询问
{
ea[k].u = u; ea[k].v = v; ea[k].lca = -;
ea[k].next = __head[u]; __head[u] = k++;
u = u^v; v = u^v; u = u^v; ///看上去深奥。。其实就是swap(u,v);
ea[k].u = u; ea[k].v = v; ea[k].lca = -;
ea[k].next = __head[u]; __head[u] = k++;
} int Find(int x)
{
return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
void Union(int u ,int v)
{
int x = Find(u);
int y = Find(v);
fa[x] = y;
} void Tarjan(int u)
{
vis[u] = true;
ance[u] = fa[u] = u; //可写为 ance[Find(u)] = fa[u] = u;
for(int k=head[u]; k!=-; k=e[k].next)
if( !vis[e[k].v] )
{
int v = e[k].v , w = e[k].w;
dir[v] = dir[u] + w;
Tarjan(v);
Union(u,v);
ance[Find(u)] = u; //可写为ance[u] = u; //甚至不要这个语句都行
}
for(int k=__head[u]; k!=-; k=ea[k].next)
if( vis[ea[k].v] )
{
int v = ea[k].v;
ea[k].lca = ea[k^].lca = ance[Find(v)];
}
} int main()
{
int k,n,q;
while(scanf("%d%d%d",&n,&k,&q)!=EOF){ memset(head,-,sizeof(head));
memset(__head,-,sizeof(__head));
int tot = ;
for(int i=; i<k; i++) //建树
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w,tot);
}
tot = ;
for(int i=; i<q; i++) //拆开保存询问
{
int u,v;
scanf("%d%d",&u,&v);
add_ask(u,v,tot);
}
memset(vis,,sizeof(vis));
for(int i=;i<=n;i++){ ///访问每个节点
if(!vis[i]){
dir[i]=;
Tarjan(i);
}
}
for(int i=; i<q; i++)
{
int s = i * , u = ea[s].u , v = ea[s].v , lca = ea[s].lca; ///s代表偶数边,奇偶只是方向不同罢了,所以取一个就行
if(fa[u]!=fa[v]) printf("Not connected\n"); ///父亲结点不同当然就不是同一棵子树了
else printf("%d\n",dir[u]+dir[v]-*dir[lca]);
}
} return ;
}
LCA离线算法Tarjan的模板的更多相关文章
- LCA离线算法Tarjan详解
离线算法也就是需要先把所有查询给保存下来,最后一次输出结果. 离线算法是基于并查集实现的,首先就是初始化P[i] = i. 接下来对于每个点进行dfs: ①首先判断是否有与该点有关的查询,如果当前该点 ...
- 距离LCA离线算法Tarjan + dfs + 并查集
距离B - Distance in the Tree 还是普通的LCA但是要求的是两个节点之间的距离,学到了一些 一开始我想用带权并查集进行优化,但是LCA合并的过程晚于离线计算的过程,所以路径长度会 ...
- HDU 2874 LCA离线算法 tarjan算法
给出N个点,M条边.Q次询问 Q次询问每两点之间的最短距离 典型LCA 问题 Marjan算法解 #include "stdio.h" #include "strin ...
- POJ1986 DistanceQueries 最近公共祖先LCA 离线算法Tarjan
这道题与之前那两道模板题不同的是,路径有了权值,而且边是双向的,root已经给出来了,就是1,(这个地方如果还按之前那样来计算入度是会出错的.数据里会出现多个root...数据地址可以在poj的dis ...
- Tarjan的LCA离线算法
LCA(Least Common Ancestors)是指树结构中两个结点的最低的公共祖先.而LCA算法则是用于求两个结点的LCA.当只需要求一对结点的LCA时,我们很容易可以利用递归算法在O(n)的 ...
- LCA 离线的Tarjan算法 poj1330 hdu2586
LCA问题有好几种做法,用到(tarjan)图拉算法的就有3种.具体可以看邝斌的博客.http://www.cnblogs.com/kuangbin/category/415390.html 几天的学 ...
- LCA(最近公共祖先)离线算法Tarjan+并查集
本文来自:http://www.cnblogs.com/Findxiaoxun/p/3428516.html 写得很好,一看就懂了. 在这里就复制了一份. LCA问题: 给出一棵有根树T,对于任意两个 ...
- poj1330+hdu2586 LCA离线算法
整整花了一天学习了LCA,tarjan的离线算法,就切了2个题. 第一题,给一棵树,一次查询,求LCA.2DFS+并查集,利用深度优先的特点,回溯的时候U和U的子孙的LCA是U,U和U的兄弟结点的子孙 ...
- Closest Common Ancestors---poj1470(LCA+离线算法)
题目链接:http://poj.org/problem?id=1470 题意是给出一颗树,q个查询,每个查询都是求出u和v的LCA: 以下是寻找LCA的预处理过程: void LCA(u){ f ...
随机推荐
- 「LibreOJ NOIP Round #1」七曜圣贤
题目啰嗦:支持三个操作: 不可重复集合:1.加入一个数 2.删除一个数 3.恢复目前最早的一次删除的数 操作可能不合法,每次有效操作之后求集合的mex(最小没有出现过的数) 50组数据+1e6,必须O ...
- [NOI2017]蔬菜——时光倒流+贪心
题目链接 题解: 貌似一眼看过去是一个贪心. 其他的算法要记录的东西就太多了. 部分分其实很高.但是没有什么提示. 想一些套路:二分?不行还要贪心判断. 分治?前后取法是有影响的. 时光倒流? 也许可 ...
- Unresolved import *** (models) error on Eclipse
Eclipse version: Oxygen.2 Release (4.7.2) Python version: 3.6 问题:系统提示:from django.db import models 语 ...
- HTTP的特点?
(1)HTTP是无连接: 无连接的含义是限制每次连接只处理一个请求.服务器处理完客户的请求,并收到客户的应答后,即断开连接.采用这种方式可以节省传输时间. (2)HTTP是媒体独立的: 这意味着,只要 ...
- Matrix.(POJ-2155)(树状数组)
题目是让每次对一个子矩阵进行翻转(0变1,1变0), 然后有多次询问,询问某个点是0还是1 这题可以用二维的树状数组来解决,考虑传统的树状数组是改变某个点,然后查询某一段, 而这个题是改变某一段,查询 ...
- Transformation 线段树好题 好题 (独立写出来对线段树不容易)
Transformation Time Limit: 15000/8000 MS (Java/Others) Memory Limit: 65535/65536 K (Java/Others)T ...
- Codeforces Round #403 (Div. 2) B 三分 C dfs
B. The Meeting Place Cannot Be Changed time limit per test 5 seconds memory limit per test 256 megab ...
- 读取txt内容放入set中
package pingbi; /** * 将txt文本读入导入到set中 * 问题: * 第一个地方有会多一个 ?--解决问题很简单,但不知道问题的原因 */ import java.io.Buff ...
- SpringBoot打war包并部署到tomcat下运行
一.修改pom.xml. 1.packaging改为war 2.build节点添加<finalName>你的项目名</finalName> 二.修改项目启动类,继承Spring ...
- [Luogu 2073] 送花
很容易想到的平衡树,加个维护区间和. 只需要插入和删除操作即可. kth其实都不用的,最小和最大可以从根节点log n一直向左/一直向右跑到叶子节点而求得. 记得每插入完一个点一定要更新区间和!!更新 ...