HDU 2586 How far away ?(LCA模板 近期公共祖先啊)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586
unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road
connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
2
3 2
1 2 10
3 1 15
1 2
2 3 2 2
1 2 100
1 2
2 1
10
25
100
100
题意:
一个村庄有 n 个房子和 n-1 条双向路,每两个房子之间都有一条简单路径。
如今有m次询问。求两房子之间的距离。
PS:
能够用LCA来解,首先找到u, v 两点的lca,然后计算一下距离值就能够了。
计算方法是。记下根结点到随意一点的距离dis[i],
这样ans = dis[u] + dis[v] - 2 * dis[lca(v, v)]了。
这题要用c++交。G++会爆栈!
代码例如以下:看别人的模板(tarjan 离线)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 40047
#define maxm 247 struct node
{
int to,w,next;
} edge[maxn*2]; int n, m; //点数,询问次数
int head[maxn];
int k;
int fa[maxn]; //父亲结点
int dis[maxn]; //到根节点距离
int vis[maxn]; //是否訪问过
int s[maxm]; //询问起点
int e[maxm]; //询问终点
int lca[maxm]; //LCA(s,e) 近期公共祖先 int find(int x)
{
if(fa[x]!=x) return fa[x]=find(fa[x]);
return fa[x];
} void init()
{
k = 1;
memset(head,0,sizeof(head));
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
} void add(int u,int v,int w)
{
edge[k].to = v;
edge[k].w = w;
edge[k].next = head[u];
head[u] = k++;
} void tarjan(int u)
{
int i,v;
fa[u] = u;
vis[u] = 1;
for(i = 0; i < m; i++)
{
if(e[i]==u && vis[s[i]])
lca[i] = find(s[i]); //若询问的两点中有一点已被訪问过。则两点的LCA则为这一点的当前父节点
if(s[i]==u && vis[e[i]])
lca[i] = find(e[i]);
}
for(i = head[u]; i; i = edge[i].next)
{
v = edge[i].to;
if(!vis[v]) //若没被訪问过
{
dis[v] = dis[u]+edge[i].w;//更新距离
tarjan(v);
fa[v] = u;//回溯更新父节点
}
}
} int main()
{
int t;
scanf("%d",&t);
while(t--)
{
init();
scanf("%d%d",&n,&m);
int u, v, w;
for(int i = 0; i < n-1; i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
for(int i = 0; i < m; i++)
{
scanf("%d%d",&s[i],&e[i]);
}
tarjan(1); for(int i = 0; i < m; i++)
{
printf("%d\n",dis[s[i]]+dis[e[i]]-2*dis[lca[i]]);//两点距离为根节点到两点距离之和-根节点到LCA距离*2
}
}
return 0;
}
(ST在线算法 转)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
//#pragma comment(linker, "/STACK:102400000,102400000") //不须要申请系统栈
const int N = 40010;
const int M = 25;
int dp[2*N][M]; //这个数组记得开到2*N,由于遍历后序列长度为2*n-1
bool vis[N];
struct edge
{
int u,v,w,next;
} e[2*N];
int tot,head[N];
inline void add(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++;
}
int ver[2*N],R[2*N],first[N],dir[N];
//ver:节点编号 R:深度 first:点编号位置 dir:距离
void dfs(int u ,int dep)
{
vis[u] = true;
ver[++tot] = u;
first[u] = tot;
R[tot] = dep;
for(int k=head[u]; k!=-1; k=e[k].next)
if( !vis[e[k].v] )
{
int v = e[k].v , w = e[k].w;
dir[v] = dir[u] + w;
dfs(v,dep+1);
ver[++tot] = u;
R[tot] = dep;
}
}
void ST(int n)
{
for(int i=1; i<=n; i++)
dp[i][0] = i;
for(int j=1; (1<<j)<=n; j++)
{
for(int i=1; i+(1<<j)-1<=n; i++)
{
int a = dp[i][j-1] , b = dp[i+(1<<(j-1))][j-1];
dp[i][j] = R[a]<R[b]?a:b;
}
}
}
//中间部分是交叉的。
int RMQ(int l,int r)
{
int k=0;
while((1<<(k+1))<=r-l+1)
k++;
int a = dp[l][k], b = dp[r-(1<<k)+1][k]; //保存的是编号
return R[a]<R[b]?a:b;
} int LCA(int u ,int v)
{
int x = first[u] , y = first[v];
if(x > y) swap(x,y);
int res = RMQ(x,y);
return ver[res];
} int main()
{
//freopen("Input.txt","r",stdin);
//freopen("Out.txt","w",stdout);
int cas;
scanf("%d",&cas);
while(cas--)
{
int n,q,num = 0;
scanf("%d%d",&n,&q);
memset(head,-1,sizeof(head));
memset(vis,false,sizeof(vis));
for(int i=1; i<n; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w,num);
}
tot = 0;
dir[1] = 0;
dfs(1,1);
/*printf("节点ver "); for(int i=1; i<=2*n-1; i++) printf("%d ",ver[i]); cout << endl;
printf("深度R "); for(int i=1; i<=2*n-1; i++) printf("%d ",R[i]); cout << endl;
printf("首位first "); for(int i=1; i<=n; i++) printf("%d ",first[i]); cout << endl;
printf("距离dir "); for(int i=1; i<=n; i++) printf("%d ",dir[i]); cout << endl;*/
ST(2*n-1);
while(q--)
{
int u,v;
scanf("%d%d",&u,&v);
int lca = LCA(u,v);
printf("%d\n",dir[u] + dir[v] - 2*dir[lca]);
}
}
return 0;
}
HDU 2586 How far away ?(LCA模板 近期公共祖先啊)的更多相关文章
- LCA模板 ( 最近公共祖先 )
LCA 有几种经典的求取方法.这里只给出模板,至于原理我完全不懂. 1.RMQ转LCA.复杂度O(n+nlog2n+m) 大致就是 DFS求出欧拉序 => 对欧拉序做ST表 => LCA( ...
- UVA - 11354Bond最小生成树,LCA寻找近期公共祖先
看懂题目意思.他的意思是求将全部的城市走一遍,危急度最小.而且给 你两个s,t后让你求在走的时候,从s到t过程中危急度最大的值,并输出它, 然后就是怎样攻克了,这个题目能够说简单,也能够说难 通过思考 ...
- LintCode 近期公共祖先
中等 近期公共祖先 查看执行结果 34% 通过 给定一棵二叉树,找到两个节点的近期公共父节点(LCA). 近期公共祖先是两个节点的公共的祖先节点且具有最大深度. 您在真实的面试中是否遇到过这个题? Y ...
- 连通分量模板:tarjan: 求割点 && 桥 && 缩点 && 强连通分量 && 双连通分量 && LCA(近期公共祖先)
PS:摘自一不知名的来自大神. 1.割点:若删掉某点后.原连通图分裂为多个子图.则称该点为割点. 2.割点集合:在一个无向连通图中,假设有一个顶点集合,删除这个顶点集合,以及这个集合中全部顶点相关联的 ...
- LCA近期公共祖先
LCA近期公共祖先 该分析转之:http://kmplayer.iteye.com/blog/604518 1,并查集+dfs 对整个树进行深度优先遍历.并在遍历的过程中不断地把一些眼下可能查询到的而 ...
- POJ 1470 Closest Common Ancestors【近期公共祖先LCA】
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u013912596/article/details/35311489 题目链接:http://poj ...
- 近期公共祖先(LCA)——离线Tarjan算法+并查集优化
一. 离线Tarjan算法 LCA问题(lowest common ancestors):在一个有根树T中.两个节点和 e&sig=3136f1d5fcf75709d9ac882bd8cfe0 ...
- LCA 近期公共祖先 小结
LCA 近期公共祖先 小结 以poj 1330为例.对LCA的3种经常使用的算法进行介绍,分别为 1. 离线tarjan 2. 基于倍增法的LCA 3. 基于RMQ的LCA 1. 离线tarjan / ...
- POJ1330Nearest Common Ancestors——近期公共祖先(离线Tarjan)
http://poj.org/problem? id=1330 给一个有根树,一个查询节点(u,v)的近期公共祖先 836K 16MS #include<iostream> #includ ...
随机推荐
- 使用IDEA 搭建一个SpringBoot + Hibernate + Gradle
---恢复内容开始--- 打开IDEA创建一个新项目: 第一步: 第二步: 第三步: 最后一步: 如果下载的时候时间太久.可以找到build.gradle文件,添加以下代码.如下图 maven{ ur ...
- Vue蚂蜂窝Vue-cli+webpack做的
先来看下效果 项目地址 喜欢star一下哦
- ESB报文自动生成工具
为了提高日常工作效率,自己在闲暇时间写了一款工具,功能界面如下图所示: 从ESB文档中复制报文字段.字段类型.报文字段注释,选择生成文件路径并输入文件名: 输入完毕后点击生成按钮,自动生成Contex ...
- Android 解决小米手机Android Studio安装app 报错的问题It is possible that this issue is resolved by uninstalling an existi
Android Studio升级到2.3版本之后,小米手机MIUI8不能运行Android Studio程序,报如下错误: Installation failed with message Faile ...
- VMWare虚拟机Centos 6.9中的 linux 配置静态ip地址上外网
1.查看网络 # ifconfig 发现网络还没有配置,ping不通 2.修改网卡配置文件 # vim /etc/sysconfig/network-scripts/ifcfg-eth0 添加如下配置 ...
- 元信息标记---meta
位于<head></head>之间 1.设置页面关键字: <meta name="keywords" content="输入具体关键字&qu ...
- MatLab之HDL coder
1 Workflow The workflow for applying HDL code generation to the hardware design process requires the ...
- svn命令行批量删除和批量添加
svn命令行批量删除和批量添加 如果使用svn的命令行,例如在linux下的终端中使用,svn的添加命令是svn add,删除命令是svn del,但是缺乏批量的操作,如果我在资源管理器中,手动添加了 ...
- Python中join函数和os.path.join用法
Python中有join和os.path.join()两个函数,具体作用如下: join:连接字符串数组.将字符串.元组.列表中的元素以指定的字符(分隔符)连接生成一个新的字符串 os.path.jo ...
- 原生js通过最外层id获取下面指定的子元素
需求:在vue中使用v-for循环出来的元素,设置动态id,之后获取下面的所有textarea标签 template: <table cellpadding = 2 v-for="(i ...