hdu 2874 Connections between cities [LCA] (lca->rmq)
Connections between cities
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4425 Accepted Submission(s): 1263
Problem Description
After World War X, a lot of cities have been seriously damaged, and we need to rebuild those cities. However, some materials needed can only be produced in certain places. So we need to transport these materials from city to city. For most of roads had been totally destroyed during the war, there might be no path between two cities, no circle exists as well.
Now, your task comes. After giving you the condition of the roads, we want to know if there exists a path between any two cities. If the answer is yes, output the shortest path between them.
Input
Input consists of multiple problem instances.For each instance, first line contains three integers n, m and c, 2<=n<=10000, 0<=m<10000, 1<=c<=1000000. n represents the number of cities numbered from 1 to n. Following m lines, each line has three integers i, j and k, represent a road between city i and city j, with length k. Last c lines, two integers i, j each line, indicates a query of city i and city j.
Output
For each problem instance, one line for each query. If no path between two cities, output “Not connected”, otherwise output the length of the shortest path between them.
Sample Input
5 3 2
1 3 2
2 4 3
5 2 3
1 4
4 5
Sample Output
Not connected
6
题意:给你n给点,m条边,有c次询问,每次询问u,v两个点,你需要判断u,v是否连通,u,v的最短距离是多少。
::对于是否连通直接用并查集就可以了,对于连通的两个点最短距离怎么求呢。
数据很大,不允许每次询问都跑一次最短路的算法,那么就考虑一下一劳永逸的办法,有没有办法经过预处理,每次询问都能快速给出答案。
注意到这是无环图,可以转化成树的做法。
对于单个连通分量随意取一点,令其为根,进行dfs遍历,得到每个点到根结点的距离,保存起来(我这里用dis保存),并且得到一个dfs遍历的序列,求出每两个点的lca。如何求lca具体看
lca –> rmq. 那么对于询问在同一个连通分量的两个的距离dis(u->v) = dis(u)+dis(v)-2*dis(lca(u,v));//u到根结点的距离+v到根结点的距离-(u,v)最早公共祖先到根结点的距离的2倍
LCA转RMQ
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = ;
int n, m, Q, fa[N], dis[N];
int id[N], fid[N], gid;
int pos, R[N], E[N<<], d[N<<][];
bool vis[N]; struct edge {
int u, v, w, next;
edge() {}
edge(int u, int v, int w, int next):u(u),v(v),w(w),next(next) {}
}e[N<<];
int ecnt, head[N]; inline void add(int u, int v, int w) {
e[ecnt] = edge(u, v, w, head[u]);
head[u] = ecnt++;
} int find(int x){
return x == fa[x] ? x : fa[x] = find(fa[x]);
} void dfs(int u, int dep){
id[u] = ++gid;
fid[gid] = u;
R[u] = ++pos;
E[pos] = id[u]; //保存dfs序列,求RMQ(lca) dis[u] = dep; // 结点u到根结点的距离
vis[u] = ;
for(int i = head[u]; ~i; i = e[i].next) {
int v = e[i].v;
if(vis[v]) continue;
dfs(v, dep + e[i].w);
E[++pos] = id[u];
}
} void init_RMQ() {
for(int i = ; i <= pos; ++i) d[i][] = E[i];
for(int j = ; (<<j) <= pos; ++j) {
for(int i = ; i + (<<j) - <= pos; ++i) {
d[i][j] = min(d[i][j-], d[i + (<<(j-))][j-]);
}
}
} inline int RMQ(int L, int R) {
if(L>R) swap(L, R);
int k = ;
while(<<(k + ) <= R - L + ) ++k;
return min(d[L][k], d[R-(<<k)+][k]);
} void solve(){
ecnt = ; gid = , pos = ;
for(int i = ; i <= n; ++i) {
head[i] = -;
fa[i] = i;
} int u, v, w;
for(int i = ; i < m; ++i) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
u = find(u), v = find(v);
fa[u] = v;
} memset(vis, , sizeof(vis));
for(int i = ; i <= n; ++i) {
if(!vis[i]) dfs(i, ); //对于每个连通块取一个根结点
}
init_RMQ(); int lca, ans;
while(Q--){
scanf("%d%d", &u, &v);
if(find(u) != find(v)) {
puts("Not connected");
}
else {
lca = fid[ RMQ(R[u], R[v]) ];
ans = dis[u] + dis[v] - *dis[lca];
printf("%d\n", ans);
}
}
} int main()
{
// freopen("in.txt", "r", stdin);
while(scanf("%d%d%d", &n, &m, &Q)>) solve();
return ;
}
tarjan离线算法


view code#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1e4+10;
const int maxc=1e6+10;
struct node{
int to,w;
node(int a=0,int b=0){to=a;w=b;}
};
int f[maxn],dis[maxn],n,ans[maxc],vis[maxn],mark[maxn];
//f[i]并查集所用,记录前继结点
//dis[i]记录个点到跟结点的距离
//ans记录m个询问的答案
//vis标记查询过了的点
//mark记录已访问过的根节点。由于已遍历的树所有结点的find都是根节点,这样就能判断下是否在别的树里了
vector<node>e[maxn];//记录树
vector<node>q[maxn];//记录所求最短距离的两点
int find(int x)
{
if(x!=f[x])f[x]=find(f[x]);
return f[x];
}
void lca(int u)
{
int i,j,k,v,c;
for(j=0;j<q[u].size();j++)
{
c=q[u][j].to;
//如果所求两点中的对应点已知,则必定在同一子树上,由于并查集只记录所在子树。所以find(c),就是最近公共祖先
if(vis[c]&&ans[q[u][j].w]==-1&&mark[find(c)]!=1)
{
//cout<<f[c]<<"***"<<endl;
ans[q[u][j].w]=dis[u]+dis[c]-2*dis[find(c)];
}
}
for(i=0;i<e[u].size();i++)
{
v=e[u][i].to;
if(vis[v])continue;
vis[v]=1;
dis[v]=dis[u]+e[u][i].w;
lca(v);//深度优先搜索
f[v]=u; }
}
int main()
{
int n,m,c;
while(scanf("%d%d%d",&n,&m,&c)!=EOF)
{
int i,j,k,x,y,z;
for(i=1;i<=n;i++)
{
e[i].clear();
q[i].clear();
f[i]=i;
vis[i]=mark[i]=0;
}
memset(ans,-1,sizeof(ans));
for(i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
e[x].push_back(node(y,z));
e[y].push_back(node(x,z));
}
for(i=1;i<=c;i++)
{
scanf("%d%d",&x,&y);
// if(x==y){ans[i]=0;continue;}
q[x].push_back(node(y,i));
q[y].push_back(node(x,i));
}
for(i=1;i<=n;i++)
{
if(!vis[i])
{
vis[i]=1;
dis[i]=0;
lca(i);
mark[i]=1;
}
}
for(i=1;i<=c;i++)
{
if(ans[i]!=-1)
printf("%d\n",ans[i]);
else
printf("Not connected\n");
}
}
return 0;
}
/*
最近公共祖先lca 离线算法/Tarjan算法,用mark标记是否在同一组里。 方法举例说明:
1
/ \
2 3
/ \
4 5
/ /
7 8
/
9
查询(4,9):到4时,由于vis[9]=0,所以继续;到9后,最近公共祖先就是f[4]=4(回溯的时候记录父节点);
查询(9,8):深度优先搜索,所以到8时才询问;要到8必须回溯到2,在进到8这个子树,所以以记录f[9]=7;f[7]=4;f[4]=2;f[2]=2;所以find(2)=2;
查询(8,3):跟上条相似,必须回溯1才能到3,而find(8)=1就是最近公共祖先;
我们可以发现,对于查询的两点,都要在先查询到的点开始,回溯到最近公共祖先,才查询相对应的点。这也就是离线算法的思路了。。
hdu 2874 Connections between cities [LCA] (lca->rmq)的更多相关文章
- hdu 2874 Connections between cities(st&rmq LCA)
Connections between cities Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (J ...
- HDU 2874 Connections between cities(LCA)
题目链接 Connections between cities LCA的模板题啦. #include <bits/stdc++.h> using namespace std; #defin ...
- HDU 2874 Connections between cities(LCA离线算法实现)
http://acm.hdu.edu.cn/showproblem.php?pid=2874 题意: 求两个城市之间的距离. 思路: LCA题,注意原图可能不连通. 如果不了解离线算法的话,可以看我之 ...
- HDU 2874 Connections between cities(LCA(离线、在线)求树上距离+森林)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2874 题目大意:给出n个点,m条边,q个询问,每次询问(u,v)的最短距离,若(u,v)不连通即不在同 ...
- HDU 2874 Connections between cities(LCA+并查集)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=2874 [题目大意] 有n个村庄,m条路,不存在环,有q个询问,问两个村庄是否可达, 如果可达则输出 ...
- hdu 2874 Connections between cities (并查集+LCA)
Connections between cities Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (J ...
- HDU 2874 Connections between cities(LCA Tarjan)
Connections between cities [题目链接]Connections between cities [题目类型]LCA Tarjan &题意: 输入一个森林,总节点不超过N ...
- hdu 2874 Connections between cities 带权lca判是否联通
Connections between cities Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (J ...
- HDU——2874 Connections between cities
Connections between cities Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (J ...
随机推荐
- JS获取屏幕高度
主要使用了document对象关于窗口的一些属性,这些属性的主要功能和用法如下. 要 得到窗口的尺寸,对于不同的浏览器,需要使用不同的属性和方法:若要检测窗口的真实尺寸,在netscape下需要使用w ...
- Linq之Lambda表达式
一 什么是LINQ? LINQ即Language Integrated Query(语言集成查询),LINQ是集成到C#和Visual Basic.NET这些语言中用于提供查询数据能力的一个新特性. ...
- 刚刚开通博客,分享Asp.Net的GridView的基本用法
包含有 数据的编辑,删除, 标题的添加,自定义分页,高亮显示鼠标所在,以及数据不足时添加空行 aspx页面代码 <asp:GridView ID="GridView1" ru ...
- ActiveReports 报表应用教程 (5)---解密电子商务领域首张电子发票的诞生(套打报表)
6月27日京东商城发布了中国电子商务领域首张电子发票,同时宣布相关系统正式上线,这标志着中国电子商务的步伐又向前迈出了重要的一步.目前“电子发票”覆盖的服务范围是在北京地区购买图书.音像商品的个人消费 ...
- Java文件编码自动转换工具类(只改变编码,不会改变文件内容)
本篇随笔主要介绍了一个用java语言写的将一个文件编码转换为另一个编码并不改变文件内容的工具类: 通过读取源文件内容,用URLEncoding重新编码解码的方式实现. public class Cha ...
- [moka同学笔记]yii2.0的下拉菜单与bootstrap下拉菜单
1.yii2下拉菜单 <li class="dropdown"><a href="#" class="dropdown-toggle ...
- JVM中显示锁基础AbstractQueuedSynchronizer
在研究AbstractQueuedSynchronizer的时候我是以ReentrantLock入手的.所以理所当然会设计到一些ReentrantLock的方法.因为网上已经有很多关于AQS的文章了, ...
- 缓存技术比拼:Redis与Memcached的同与不同
转至:http://developer.51cto.com/art/201603/507980.htm 在今天的文章中,我们将探讨Redis(REmote DIctionary Server).Red ...
- log4j.xml 配置参数属性level使用心得
jdbc.sqlonly 只显示执行的sql语句.info级才可以显示,debug增加显示java源代码位置. jdbc.sqltiming 显示执行的sql语句以及语句执行时间, ...
- C#读写ini文件操作
ini文件,是windows操作系统下的配置文件,ini文件是一种按照特点方式排列的文本文件,它的构成分为三部分,结构如下: [Section1] key 1 = value2 key 1 = val ...