BZOJ 2125: 最短路
2125: 最短路
Time Limit: 1 Sec Memory Limit: 259 MB
Submit: 756 Solved: 331
[Submit][Status][Discuss]
Description
给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径。
Input
输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个整数v,u,w表示一条无向边v-u,长度为w 最后Q行,每行两个整数v,u表示一组询问
Output
输出Q行,每行一个整数表示询问的答案
Sample Input
1 2 1
1 4 1
3 4 1
2 3 1
3 7 1
7 8 2
7 9 2
1 5 3
1 6 4
5 6 1
1 9
5 7
Sample Output
6
HINT
对于100%的数据,N<=10000,Q<=10000
Source
#include <cstdio>
#include <cstring> inline int nextChar(void)
{
static const int siz = << ; static char buf[siz];
static char *hd = buf + siz;
static char *tl = buf + siz; if (hd == tl)
fread(hd = buf, , siz, stdin); return int(*hd++);
} inline int nextInt(void)
{
int r = , c = nextChar(); for (; c < ; c = nextChar());
for (; c > ; c = nextChar())
r = r * + c - ''; return r;
} template <class T>
inline T min(const T &a, const T &b)
{
return a < b ? a : b;
} template <class T>
inline T abs(const T &x)
{
return x < ? -x : x;
} const int mxn = ;
const int inf = 0x3f3f3f3f; int n, m, q; int tot;
int hd[mxn];
int to[mxn];
int vl[mxn];
int nt[mxn]; inline void add(int x, int y, int w)
{
nt[tot] = hd[x];
to[tot] = y;
vl[tot] = w;
hd[x] = tot++;
} int dis[mxn];
int que[mxn];
int vis[mxn]; inline void spfa(void)
{
memset(vis, , sizeof vis);
memset(dis, inf, sizeof dis); int lt = , rt = ; que[rt++] = ;
vis[] = ;
dis[] = ; while (lt != rt)
{
int u = que[lt++], v; if (lt > mxn)lt = ; vis[u] = ; for (int i = hd[u]; ~i; i = nt[i])
if (v = to[i], dis[v] > dis[u] + vl[i])
{
dis[v] = dis[u] + vl[i]; if (!vis[v])
{
vis[que[rt++] = v] = ; if (rt > mxn)rt = ;
}
}
}
} struct data
{
int u, v, w; inline data(void) {};
inline data(int a, int b, int c)
: u(a), v(b), w(c) {};
}stk[mxn]; int top; int tim;
int dfn[mxn];
int low[mxn]; int cnt;
int cir[mxn];
int len[mxn];
int bel[mxn];
int fat[mxn][]; inline void addcir(int u, int v)
{
++cnt; while (u != stk[top].u && v != stk[top].v)
{
int x = stk[top].u, y = stk[top].v, w = stk[top].w; if (x != u)bel[x] = cnt, fat[x][] = u;
if (y != u)bel[y] = cnt, fat[y][] = u; len[cnt] += w, cir[x] = cir[y] + w; --top;
} {
int x = stk[top].u, y = stk[top].v, w = stk[top].w; len[cnt] += w, cir[x] = cir[y] + w; fat[y][] = x; --top;
}
} void tarjan(int u, int f)
{
dfn[u] = low[u] = ++tim; for (int i = hd[u], v; ~i; i = nt[i])
if ((v = to[i]) != f)
{
if (!dfn[v])
{
stk[++top] = data(u, v, vl[i]), tarjan(v, u); if (low[v] < low[u])low[u] = low[v]; if (low[v] >= dfn[u])addcir(u, v);
}
else if (dfn[v] < low[u])
low[u] = dfn[v], stk[++top] = data(u, v, vl[i]);
}
} int dep[mxn]; void build(int u)
{
for (int i = hd[u]; ~i; i = nt[i])
dep[to[i]] = dep[u] + , build(to[i]);
} inline void prework(void)
{
spfa(); tarjan(, ); for (int i = ; i <= ; ++i)
for (int j = ; j <= n; ++j)
fat[j][i] = fat[fat[j][i - ]][i - ]; memset(hd, -, sizeof hd), tot = ; for (int i = ; i <= n; ++i)
add(fat[i][], i, ); dep[] = , build();
} inline int getLCA(int a, int b, int &x, int &y)
{
if (dep[a] < dep[b])
a ^= b ^= a ^= b; int ret = dis[a] + dis[b]; for (int i = ; ~i; --i)
if (dep[fat[a][i]] >= dep[b])
a = fat[a][i]; if (a == b)
return x = y = a, ret - dis[a] * ; for (int i = ; ~i; --i)
if (fat[a][i] != fat[b][i])
a = fat[a][i],
b = fat[b][i]; return x = a, y = b, ret - dis[fat[a][]] * ;
} signed main(void)
{
n = nextInt();
m = nextInt();
q = nextInt(); memset(hd, -, sizeof(hd)), tot = ; for (int i = ; i <= m; ++i)
{
int x = nextInt();
int y = nextInt();
int w = nextInt(); add(x, y, w);
add(y, x, w);
} prework(); for (int i = , x, y; i <= q; ++i)
{
int a = nextInt();
int b = nextInt(); int ans = getLCA(a, b, x, y); if (bel[x] && bel[x] == bel[y])
{
ans = dis[a] + dis[b] - dis[x] - dis[y]; int len1 = abs(cir[x] - cir[y]);
int len2 = len[bel[x]] - len1; ans += min(len1, len2);
} printf("%d\n", ans);
}
}
@Author: YouSiki
BZOJ 2125: 最短路的更多相关文章
- bzoj 2125 最短路——仙人掌两点间最短路
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2125 因为看了TJ又抄了标程,现在感觉还是轻飘飘的……必须再做一遍. 两点间的情况: 1.直 ...
- 【刷题】BZOJ 2125 最短路
Description 给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径. Input 输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个 ...
- BZOJ.2125.最短路(仙人掌 最短路Dijkstra)
题目链接 多次询问求仙人掌上两点间的最短路径. 如果是在树上,那么求LCA就可以了. 先做着,看看能不能把它弄成树. 把仙人掌看作一个图(实际上就是),求一遍根节点到每个点的最短路dis[i]. 对于 ...
- bzoj 2125 最短路 点双 圆方树
LINK:最短路 一张仙人掌图 求图中两点最短路. \(n<=10000,Q<=10000,w>=1\) 考虑边数是多少 m>=n-1 对于一张仙人掌图 考虑先构建出来dfs树 ...
- BZOJ.2125.最短路(仙人掌 圆方树)
题目链接 圆方树.做题思路不写了.. 就是当LCA是方点时跳进那个环可以分类讨论一下用树剖而不必须用倍增: 如果v是u的(唯一的那个)重儿子,那么u的DFS序上+1的点即是要找的:否则v会引出一条新的 ...
- bzoj 1023: [SHOI2008]cactus仙人掌图 2125: 最短路 4728: 挪威的森林 静态仙人掌上路径长度的维护系列
%%% http://immortalco.blog.uoj.ac/blog/1955 一个通用的写法是建树,对每个环建一个新点,去掉环上的边,原先环上每个点到新点连边,边权为点到环根的最短/长路长度 ...
- 【BZOJ】2125: 最短路 圆方树(静态仙人掌)
[题意]给定带边权仙人掌图,Q次询问两点间最短距离.n,m,Q<=10000 [算法]圆方树处理仙人掌问题 [题解]树上的两点间最短路问题,常用倍增求LCA解决,考虑扩展到仙人掌图. 先对仙人掌 ...
- Bzoj 3694: 最短路 树链剖分
3694: 最短路 Time Limit: 5 Sec Memory Limit: 256 MBSubmit: 67 Solved: 34[Submit][Status][Discuss] Des ...
- bzoj3047: Freda的传呼机 && 2125: 最短路
Description 为了随时与rainbow快速交流,Freda制造了两部传呼机.Freda和rainbow所在的地方有N座房屋.M条双向光缆.每条光缆连接两座房屋,传呼机发出的信号只能沿着光缆传 ...
随机推荐
- WPF编程 ,TextBlock 显示百分数值的一种简单方法。
原文:WPF编程 ,TextBlock 显示百分数值的一种简单方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/article/ ...
- 洛咕 P2336 [SCOI2012]喵星球上的点名
洛咕 P2336 [SCOI2012]喵星球上的点名 先求出SA和height,一个点名串对应的就是一段区间,还有很多个点,就转化成了 有很多个区间,很多个点集,对每个区间计算和多少个点集有交,对每个 ...
- 数据库历险记(二) | Redis 和 Mecached 到底哪个好?
文章首发于微信公众号「陈树义」,专注于 Java 技术分享的社区.点击链接扫描二维码,与500位小伙伴一起共同进步.微信公众号二维码 http://p3npq6ecr.bkt.clouddn.com/ ...
- ABPZERO介绍
内容 首先我们创建一个名为"Acme.PhoneBook"的项目. 本文档是指南会同步开发您的项目. 我们建议你在开发之前准备备份下这份初始项目. 因为abpZero是基于abp的 ...
- Jenkins下载安装
Jenkins是什么? Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台.这是一个免费的源代码,可以处理任何类型的构建或持续集成.集成Jenkins可以用于一些测 ...
- cocos2d-x学习之路(三)——精灵与动作
这里我们来看看所有游戏引擎中都会出现的一个重要的概念——精灵
- 重磅发布丨乐维监控:全面兼容云平台,助力企业DevOps转型升级!
2019年伊始,我们迎来了乐维监控的又一重大功能更新——云平台监控,这将有效帮助企业将云上.云下数据聚合,方便统一化的监控管理与维护!未来,乐维监控每一次的产品功能及版本更新,我们都将第一时间于此发布 ...
- k8s之使用secret获取私有仓库镜像
一.前言 其实这次实践算不上特别复杂,只是在实践过程中遇到了一些坑,以及填坑的方法是非常值得在以后的学习过程中参考借鉴的 二.知识准备 1.harbor是一个企业级的镜像仓库,它比起docker re ...
- Four-Operations
开发环境:Eclipse 结对小伙伴:201306114416 陈键 (http://www.cnblogs.com/be-the-one/) 201306114452 吴舒婷 (http://www ...
- Answer My Questions
回答自己的问题,真棒!断电让自己的工作重来.真棒! 阅读以前自己的博客,发现问题都已经有了答案. (1).想要成为一名专业的软件工程师,首先得是有相关的资格证书,这个可以通过软考获得.然后在职场中锻炼 ...