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

  1. hdu 2874 Connections between cities(st&rmq LCA)

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

  2. HDU 2874 Connections between cities(LCA)

    题目链接 Connections between cities LCA的模板题啦. #include <bits/stdc++.h> using namespace std; #defin ...

  3. HDU 2874 Connections between cities(LCA离线算法实现)

    http://acm.hdu.edu.cn/showproblem.php?pid=2874 题意: 求两个城市之间的距离. 思路: LCA题,注意原图可能不连通. 如果不了解离线算法的话,可以看我之 ...

  4. HDU 2874 Connections between cities(LCA(离线、在线)求树上距离+森林)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2874 题目大意:给出n个点,m条边,q个询问,每次询问(u,v)的最短距离,若(u,v)不连通即不在同 ...

  5. HDU 2874 Connections between cities(LCA+并查集)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=2874 [题目大意] 有n个村庄,m条路,不存在环,有q个询问,问两个村庄是否可达, 如果可达则输出 ...

  6. hdu 2874 Connections between cities (并查集+LCA)

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

  7. HDU 2874 Connections between cities(LCA Tarjan)

    Connections between cities [题目链接]Connections between cities [题目类型]LCA Tarjan &题意: 输入一个森林,总节点不超过N ...

  8. hdu 2874 Connections between cities 带权lca判是否联通

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

  9. HDU——2874 Connections between cities

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

随机推荐

  1. 无意中在sql日志中发现如下内容,

    日期,源,严重性,消息01/06/2015 09:06:13,登录,未知,Length specified in network packet payload did not match number ...

  2. Worm.Win32.DownLoader.ns病毒主进程新式输入法注入分析(IME Inject)

    1.病毒会在system32目录生成一个以tmp结尾的随机数命名的文件. 2.然后挂钩HOOK本进程空间的imm32.dll导出的ImmLoadLayout函数和ntdll.dll导出的ZwQuery ...

  3. Oracle数据库常用设置积累

    1.在oracle的之前版本时, 你的用户名密码是大小写不敏感的, 但在11g中, 数据库默认密码的大小写是敏感的,去除oracle的密码大写敏感设定: alter system set sec_ca ...

  4. 从零开始学习Linux(ls命令)

    学习Linux已经两年了,可是仍然是小白一个.用过很多命令,可是很多都没记住,基础不扎实,很大程度上是不记笔记,得过且过. 从今天起,开始整理Linux笔记. Linux每个命令都有--help这个选 ...

  5. ahjesus解决win下U盘无法写入的问题

    可能是由于不同品牌的U盘出厂时磁盘分区和格式化方式不同而引起的兼容性问题.解决方案如下 启动cmd.输入diskpart,启动DISKPART工具 在DISKPART窗口中输入以下命令: >li ...

  6. IT外包行业与职业发展

          在IT行业,总是有一些IT外包公司的存在,凡是存在的都是合理的.当你做为IT从业人员应该尽量避免去外包公司工作 .特别是你从事软件开发工作.     先来说说缘由,一些外包公司本来是从事软 ...

  7. JS中检测数据类型的几种方式及优缺点

    1.typeof 用来检测数据类型的运算符 typeof value 返回值首先是一个字符串,其次里面包含了对应的数据类型,例如:"number"."string&quo ...

  8. sass开发过程中遇到的几个坑

    1.安装sass被墙的问题 安装完`ruby`后,打开`ruby cmd` 输入`gem install sass`,安装失败,有可能是镜像源的问题,也有可能是墙的问题. 因为公司内网的奇葩限制,各种 ...

  9. javascript --- 词法分析

    JavaScript代码自上而下执行,但是在js代码执行前,会首先进行词法分析,所以事实上,js运行要分为词法分析和执行两个阶段. 词法分析主要分为三步: 第一步: 分析形参: 第二步: 分析变量声明 ...

  10. Android APK 文件自动安装

    1.权限 <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> 2.方法 Uri ...