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. 征战jQuery

    一:jQuery的用途 1>.访问 和 操作 DOM元素 2>.控制 页面样式 3>.对页面事件的处理 4>.方便的使用jQuery插件 5>.与Ajax技术的完美结合 ...

  2. call和apply第一个参数为null/undefined,函数this指向全局对象

    call和apply第一个参数为null/undefined,函数this指向全局对象,在浏览器中是window,在node中是global 在严格模式中(ie 6/7/8/9 除外),传入null/ ...

  3. bzoj3810: [Coci2015]Stanovi(记忆化搜索)

    实际上切出来的矩阵在原矩阵上的位置是不重要的...重要的只有矩阵的大小和上下左右是否在边界上. 于是我们可以设f[x][y][l][r][u][d]表示x*y的矩阵上下左右是不是边界的最小代价. 记忆 ...

  4. bzoj3524: [Poi2014]Couriers(主席树)

    主席树(可持久化权值线段树)初探... 修改一个点只对树上logn个点有影响,所以新建logn个点就行了,总共新建mlogn个点. 查询一个区间[l,r],相当于将数一个一个加进树,询问第l到第r次操 ...

  5. JQuery仿淘宝滚动加载图片

    用 JQuery 制作随着显示页面的滚动条的滚动动态加载图片,适用于图片太多的页面,在访问网页时,可以先只加载第一屏要显示的图片,当用户进行向下滚动查看页面的时候,动态去加载这些图片,好处是减少页面第 ...

  6. CentOS 6.5 下安装 QT 4

    1. 获取下载地址 从我到网盘下载:  qt-creator-opensource-linux-x86_64-3.5.1.run            qt-everywhere-opensource ...

  7. k好数 数位dp

    问题描述 如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数.求L位K进制数中K好数的数目.例如K = 4,L = 2的时候,所有K好数为11.13.20.22 ...

  8. JAVA对象的深度克隆

    有时候,我们需要把对象A的所有值复制给对象B(B = A),但是这样用等号给赋值你会发现,当B中的某个对象值改变时,同时也会修改到A中相应对象的值! 也许你会说,用clone()不就行了?!你的想法只 ...

  9. 学习opencv-------函数使用二(图像变换)

    #include"cv.h" #include"highgui.h" using namespace cv; void CVFILTER2D(IplImage ...

  10. Lodash js数据操作库

    https://lodash.com/docs/4.17.4