POJ1986(LCA应用:求两结点之间距离)
| Time Limit: 2000MS | Memory Limit: 30000K | |
| Total Submissions: 11304 | Accepted: 3985 | |
| Case Time Limit: 1000MS | ||
Description
Input
* Line 2+M: A single integer, K. 1 <= K <= 10,000
* Lines 3+M..2+M+K: Each line corresponds to a distance query and contains the indices of two farms.
Output
Sample Input
7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
3
1 6
1 4
2 6
Sample Output
13
3
36
学习LCA的好文章:http://taop.marchtea.com/04.04.html
离线:将所有查询输入完毕后再统一输出结果。
在线:查询一个输出一个。 dfs+并查集,离线
#include <cstdio>
#include <vector>
using namespace std;
const int MAXN=;
int n,m,k;
struct Edge{
int to,w;
Edge(){}
Edge(int to,int w)
{
this->to=to;
this->w=w;
}
};
vector<Edge> arc[MAXN]; struct Node{
int to,id;
Node(){}
Node(int to,int id)
{
this->to=to;
this->id=id;
}
};
vector<Node> que[MAXN]; int par[MAXN];
void prep()
{
for(int i=;i<MAXN;i++)
{
d[i]=;
vis[i]=;
par[i]=i;
}
}
int fnd(int x)
{
if(par[x]==x)
{
return x;
}
return par[x]=fnd(par[x]);
}
void unite(int fa,int son)
{
int a=fnd(fa);
int b=fnd(son);
par[b]=a;
} int vis[MAXN],d[MAXN];
int res[MAXN];
void tarjan(int u)
{
vis[u]=;
for(int i=,size=que[u].size();i<size;i++)
{
Node nod=que[u][i];
if(vis[nod.to])
{
int lca=fnd(nod.to);
res[nod.id]=d[nod.to]+d[u]-*d[lca];
}
}
for(int i=,size=arc[u].size();i<size;i++)
{
Edge e=arc[u][i];
if(!vis[e.to])
{
d[e.to]=d[u]+e.w;
tarjan(e.to);
unite(u,e.to);
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
prep();
for(int i=;i<=n;i++) arc[i].clear();
for(int i=;i<m;i++)
{
int u,v,w;
scanf("%d %d %d %*c",&u,&v,&w);
arc[u].push_back(Edge(v,w));
arc[v].push_back(Edge(u,w));
}
scanf("%d",&k);
for(int i=;i<k;i++)
{
int u,v;
scanf("%d%d",&u,&v);
que[v].push_back(Node(u,i));
que[u].push_back(Node(v,i));
}
for(int i=;i<=n;i++)
{
if(!vis[i])
{
tarjan(i);
}
}
for(int i=;i<k;i++)
{
printf("%d\n",res[i]);
}
}
return ;
}
模板:RMQ求LCA在线算法(稀疏表实现RMQ)
#include <cstdio>
#include <cstring>
#include <vector>
#include <math.h>
#include <algorithm>
using namespace std;
const int MAXN=;
int n,m,k;
struct Edge{
int to,w;
Edge(){}
Edge(int to,int w)
{
this->to=to;
this->w=w;
}
};
vector<Edge> arc[MAXN]; int vs[MAXN+MAXN],depth[MAXN+MAXN],first[MAXN],tot;
int d[MAXN],vis[MAXN];
void dfs(int u,int dep)
{
vis[u]=;
vs[++tot]=u;
depth[tot]=dep;
first[u]=tot;
for(int i=,size=arc[u].size();i<size;i++)
{
Edge e=arc[u][i];
if(!vis[e.to])
{
d[e.to]=d[u]+e.w;
dfs(e.to,dep+);
vs[++tot]=u;
depth[tot]=dep;
}
}
} int dp[MAXN+MAXN][];
void init_st(int size)
{
for(int i=;i<=size;i++) dp[i][]=i;
for(int j=;j<;j++)
{
for(int i=;i<=size;i++)
{
if(i+(<<j)-<=size)
{
int a=dp[i][j-];
int b=dp[i+(<<(j-))][j-];
dp[i][j]=depth[a]<depth[b]?a:b;
}
}
}
}
int rmq_st(int l,int r)
{
int limit=(int)(log(r-l+1.0)/(log(2.0)));
int a=dp[l][limit];
int b=dp[r-(<<limit)+][limit];
return depth[a]<depth[b]?a:b;
} int LCA(int u,int v)
{
if(first[u]>first[v]) swap(u,v);
int id=rmq_st(first[u],first[v]);
return vs[id];
} int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
tot=;
memset(vis,,sizeof(vis));
memset(d,,sizeof(d));
for(int i=;i<=n;i++) arc[i].clear();
for(int i=;i<m;i++)
{
int u,v,w;
scanf("%d %d %d %*c",&u,&v,&w);
arc[u].push_back(Edge(v,w));
arc[v].push_back(Edge(u,w));
}
for(int i=;i<=n;i++)
{
if(!vis[i])
{
dfs(i,);
}
}
init_st(tot);
scanf("%d",&k);
for(int i=;i<k;i++)
{
int u,v;
scanf("%d%d",&u,&v);
int lca=LCA(u,v);
int res=d[u]+d[v]-*d[lca];
printf("%d\n",res);
}
}
return ;
}
POJ1986(LCA应用:求两结点之间距离)的更多相关文章
- hdoj 1869 六度分离【最短路径求两两边之间最长边】
六度分离 Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- 求两个数之间的质数 -----------基于for循环 算法思想
前端代码: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.as ...
- js求连个数之间的数字
整理出自项目中一个需求,求两个数之间的数字. const week = function(arr,arr2){ let a=parseInt(arr); let b=parseInt(arr2); l ...
- 「POJ-3608」Bridge Across Islands (旋转卡壳--求两凸包距离)
题目链接 POJ-3608 Bridge Across Islands 题意 依次按逆时针方向给出凸包,在两个凸包小岛之间造桥,求最小距离. 题解 旋转卡壳的应用之一:求两凸包的最近距离. 找到凸包 ...
- 求两点之间距离 C++
求两点之间距离(20 分) 定义一个Point类,有两个数据成员:x和y, 分别代表x坐标和y坐标,并有若干成员函数. 定义一个函数Distance(), 用于求两点之间的距离.输入格式: 输入有两行 ...
- 旋转卡壳求两个凸包最近距离poj3608
#include <iostream> #include <cmath> #include <vector> #include <string.h> # ...
- JavaScript求两个数字之间所有数字的和
这是在fcc上的中级算法中的第一题,拉出来的原因并不是因为有什么好说的,而是我刚看时以为是求两个数字的和, 很显然错了.我感觉自己的文字理解能力被严重鄙视了- -.故拉出来折腾折腾. 要求: 给你一个 ...
- GPS(2)关于位置的3个示例,实时获取GPS定位数据,求两个经纬点距离,邻近某个区域圆时警告
实时获取GPS定位数据 import android.app.Activity; import android.content.Context; import android.location.Loc ...
- js 求两个日期之间相差天数
//求两个日期之间的相差天数 function daysBetween(DateOne, DateTwo) { var OneMonth = DateOne.substring(5, DateOne. ...
随机推荐
- 卡特兰数-Catalan数
卡特兰数的含义: 说到卡特兰数,就不得不提及卡特兰数序列.卡特兰数序列是一个整数序列.其通项公式是我们从中取出的就叫做第n个卡特兰数数,前几个卡特兰数数是:1, 1, 2, 5, 14, 42, 13 ...
- 集群 安装 配置FastDFS
FastDFS 集群 安装 配置 这篇文章介绍如何搭建FastDFS 集群 FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载 ...
- Python 进程、线程、协程、锁机制,你知多少?
1.python的多线程到底有没有用? 2. 为什么在python里推荐使用多进程而不是多线程 3.进程.线程.协程.各种锁 4.Python多进程编程
- 九度OJ 1178:复数集合 (插入排序)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:8393 解决:1551 题目描述: 一个复数(x+iy)集合,两种操作作用在该集合上: 1.Pop 表示读出集合中复数模值最大的那个复数,如 ...
- Wix Burn运行64位dism.exe的问题
主要的问题是Burn是一个32位程序,在64位机器上它启动的进程都会被重定向到wow64目录下,也就是说它运行的dism.exe最终会是32位的.解决的方法就是用wix提供的QtExec64CmdLi ...
- linux c编程:网络编程
在网络上,通信服务都是采用C/S机制,也就是客户端/服务器机制.流程可以参考下图: 服务器端工作流程: 使用socket()函数创建服务器端通信套接口 使用bind()函数将创建的套接口与服务器地址绑 ...
- FI 常用表
FI 常用表 GL部分:FAGLFLEXT(FMGLFLEXT) 总账汇总表 GLT0 旧总帐汇总表 SKA1 总账科目主记录 (科目表) ...
- YTST_CX_0001(ALV栏位汇总)
*********************************************************************** * Title : X ...
- 关于left join遇到where就不管用的问题
今天做了个存储过程,需要的功能是查询所有人的得分,有人没分就给零分,显而易见这里用左外连接是没有问题的, 但是在连接完之后有个根据时间筛选功能,于是我加了where条件判断,这时候没有想到的事情发生了 ...
- Mongo 分组后排序取时间最大的一整条数据对象
db.getCollection('product_protocol_new').aggregate([ {$sort:{"end_date":-1}}, {$group:{ _i ...