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的模板的更多相关文章

  1. LCA离线算法Tarjan详解

    离线算法也就是需要先把所有查询给保存下来,最后一次输出结果. 离线算法是基于并查集实现的,首先就是初始化P[i] = i. 接下来对于每个点进行dfs: ①首先判断是否有与该点有关的查询,如果当前该点 ...

  2. 距离LCA离线算法Tarjan + dfs + 并查集

    距离B - Distance in the Tree 还是普通的LCA但是要求的是两个节点之间的距离,学到了一些 一开始我想用带权并查集进行优化,但是LCA合并的过程晚于离线计算的过程,所以路径长度会 ...

  3. HDU 2874 LCA离线算法 tarjan算法

    给出N个点,M条边.Q次询问 Q次询问每两点之间的最短距离 典型LCA 问题   Marjan算法解 #include "stdio.h" #include "strin ...

  4. POJ1986 DistanceQueries 最近公共祖先LCA 离线算法Tarjan

    这道题与之前那两道模板题不同的是,路径有了权值,而且边是双向的,root已经给出来了,就是1,(这个地方如果还按之前那样来计算入度是会出错的.数据里会出现多个root...数据地址可以在poj的dis ...

  5. Tarjan的LCA离线算法

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

  6. LCA 离线的Tarjan算法 poj1330 hdu2586

    LCA问题有好几种做法,用到(tarjan)图拉算法的就有3种.具体可以看邝斌的博客.http://www.cnblogs.com/kuangbin/category/415390.html 几天的学 ...

  7. LCA(最近公共祖先)离线算法Tarjan+并查集

    本文来自:http://www.cnblogs.com/Findxiaoxun/p/3428516.html 写得很好,一看就懂了. 在这里就复制了一份. LCA问题: 给出一棵有根树T,对于任意两个 ...

  8. poj1330+hdu2586 LCA离线算法

    整整花了一天学习了LCA,tarjan的离线算法,就切了2个题. 第一题,给一棵树,一次查询,求LCA.2DFS+并查集,利用深度优先的特点,回溯的时候U和U的子孙的LCA是U,U和U的兄弟结点的子孙 ...

  9. Closest Common Ancestors---poj1470(LCA+离线算法)

    题目链接:http://poj.org/problem?id=1470 题意是给出一颗树,q个查询,每个查询都是求出u和v的LCA:    以下是寻找LCA的预处理过程: void LCA(u){ f ...

随机推荐

  1. BZOJ1999 NOIP2007 洛谷P1099 P2491 SDOI 2011

    Description: 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各 ...

  2. Codeforces Round #514 (Div. 2):D. Nature Reserve(二分+数学)

    D. Nature Reserve 题目链接:https://codeforces.com/contest/1059/problem/D 题意: 在二维坐标平面上给出n个数的点,现在要求一个圆,能够容 ...

  3. HTTP的消息结构?

    参考:http://www.runoob.com/http/http-messages.html (1)请求数据包结构: 第一部分:请求行(数据包的第一行内容)[GET/HTTP/1.1] 请求行包含 ...

  4. ContentProvider学习

    1.创建类继承ContentProvider类,并实现增.删.改.查功能. public static final String AUTHORITY = "com.diysoul.lists ...

  5. tcpdump抓取ftp密码

    步骤: 1.登陆ftp服务器,执行命令: tcpdump -i wlan0 -w password.bin -c 500 port 21 2.有人登陆后,执行: tcpdump -v -XX -r p ...

  6. rename 批量重命名

    使用背景,对规则文件名批量重命名 例如: Send_Message_20160802_01_log.log Send_Message_20160802_02_log.log Send_Message_ ...

  7. vue-cli中引入jquery的方法

    vue-cli中引入jquery的方法 以前写vue项目都没有引入过jquery,今天群里面的一位小伙伴问了我这个问题,我就自己捣鼓了一下,方法如下: 我们先进入webpack.base.conf.j ...

  8. Maven-Dependency Mechanism

    依赖管理是maven的一个广为人知的特性, 这也是maven擅长的一个领域. 为单一的工程管理依赖不是很难, 但当你着手处理多模块工程和包含数十或数百个模块的应用时, maven可以帮助你很好地保持高 ...

  9. ssh无密码登录认证失败

    http://www.2cto.com/os/201401/271150.html https://unix.stackexchange.com/questions/36540/why-am-i-st ...

  10. outer的使用

    outer就是一个标签,java语言中根本没有此关键字,因此outer也可以用其它的词来代替 java中的标签就是一个紧跟着英文冒号(:)的标识符.与其他语言不同的是,java中的标签只有放在循环语言 ...