题目

给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径。

输入格式

输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个整数v,u,w表示一条无向边v-u,长度为w 最后Q行,每行两个整数v,u表示一组询问

输出格式

输出Q行,每行一个整数表示询问的答案

输入样例

9 10 2

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

输出样例

5

6

提示

对于100%的数据,N<=10000,Q<=10000

题解

仙人掌的题目,都与树上的方法相联系,再考虑环的影响

首先如果在树上,我们设d[u]表示u到根的距离,两点u,v的距离dis=d[u]+d[v]−2∗d[lca]

现在加上几个环,我们先跑一遍dfs找出所有的环以及算出d[],然后重构树,将环上的点全部连到该环最高点上,距离为环上到最高点的最短路

这样子构建出来的树,我们可以用倍增套用树的方法求解

如果求解时两点倍增时算得的最后祖先属于同一个环,那么就考虑环的贡献

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u]; k; k = ed[k].nxt)
using namespace std;
const int maxn = 10005,maxm = 100005,INF = 1000000000;
inline int RD(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
return out * flag;
} int N,M,Q,h[maxn],ne = 2;
struct EDGE{int to,nxt,w;}ed[maxm];
inline void build(int u,int v,int w){
ed[ne] = (EDGE){v,h[u],w}; h[u] = ne++;
ed[ne] = (EDGE){u,h[v],w}; h[v] = ne++;
} int h2[maxn];
struct E{int to,nxt;}e[2 * maxn];
inline void add(int u,int v){e[ne] = (E){v,h2[u]}; h2[u] = ne++;} int dfn[maxn],low[maxn],d[maxn],dep[maxn],cnt = 0;
int fa[maxn][20],dis[maxn][20];
int cir[maxn],siz[maxn];
void getcir(int rt,int k){
int to = ed[k].to,len = d[to] - d[rt] + ed[k].w;
siz[++siz[0]] = len;
for (int i = to; i != rt; i = fa[i][0]){
add(rt,i);
dis[i][0] = min(d[i] - d[rt],len - d[i] + d[rt]);
cir[i] = siz[0];
}
}
void dfs(int u){
dfn[u] = low[u] = ++cnt; int to;
Redge(u) if ((to = ed[k].to) != fa[u][0]){
if (!dfn[to]){
fa[to][0] = u;
d[to] = d[u] + ed[k].w;
dfs(to);
low[u] = min(low[u],low[to]);
}else low[u] = min(low[u],dfn[to]);
if (dfn[u] < low[to]) add(u,to),dis[to][0] = ed[k].w;
}
Redge(u) if (fa[to = ed[k].to][0] != u && dfn[u] < dfn[to])
getcir(u,k);
}
void dfs2(int u){
REP(i,15){
fa[u][i] = fa[fa[u][i - 1]][i - 1];
dis[u][i] = dis[u][i - 1] + dis[fa[u][i - 1]][i - 1];
}
for (int k = h2[u],to; k; k = e[k].nxt){
fa[to = e[k].to][0] = u; dep[to] = dep[u] + 1;
dfs2(to);
}
}
int solve(int u,int v){
if (dep[u] < dep[v]) swap(u,v);
int ans = 0,D = dep[u] - dep[v];
for (int i = 0; (1 << i) <= D; i++)
if ((1 << i) & D) ans += dis[u][i],u = fa[u][i];
if (u == v) return ans;
for (int i = 15; i >= 0; i--)
if (fa[u][i] != fa[v][i]){
ans += dis[u][i] + dis[v][i];
u = fa[u][i]; v = fa[v][i];
}
if (cir[u] && cir[u] == cir[v])
ans += min(abs(d[u] - d[v]),siz[cir[u]] - abs(d[u] - d[v]));
else ans += dis[u][0] + dis[v][0];
return ans;
}
int main(){
N = RD(); M = RD(); Q = RD(); int a,b,w;
while (M--) a = RD(),b = RD(),w = RD(),build(a,b,w);
ne = 1;
dfs(1);
dep[1] = 1;
dfs2(1);
while (Q--){
a = RD(); b = RD();
printf("%d\n",solve(a,b));
}
return 0;
}

BZOJ2125 最短路 【仙人掌最短路】的更多相关文章

  1. BZOJ.2125.最短路(仙人掌 最短路Dijkstra)

    题目链接 多次询问求仙人掌上两点间的最短路径. 如果是在树上,那么求LCA就可以了. 先做着,看看能不能把它弄成树. 把仙人掌看作一个图(实际上就是),求一遍根节点到每个点的最短路dis[i]. 对于 ...

  2. poj 3463 Sightseeing( 最短路与次短路)

    http://poj.org/problem?id=3463 Sightseeing Time Limit: 2000MS   Memory Limit: 65536K Total Submissio ...

  3. 最短路和次短路问题,dijkstra算法

    /*  *题目大意:  *在一个有向图中,求从s到t两个点之间的最短路和比最短路长1的次短路的条数之和;  *  *算法思想:  *用A*求第K短路,目测会超时,直接在dijkstra算法上求次短路; ...

  4. UESTC30-最短路-Floyd最短路、spfa+链式前向星建图

    最短路 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) 在每年的校赛里,所有进入决赛的同 ...

  5. POJ---3463 Sightseeing 记录最短路和次短路的条数

    Sightseeing Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9247   Accepted: 3242 Descr ...

  6. hdu1688(dijkstra求最短路和次短路)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1688 题意:第k短路,这里要求的是第1短路(即最短路),第2短路(即次短路),以及路径条数,最后如果最 ...

  7. CF 672C 两个人捡瓶子 最短路与次短路思想

    C. Recycling Bottles time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  8. POJ 3463 Sightseeing 【最短路与次短路】

    题目 Tour operator Your Personal Holiday organises guided bus trips across the Benelux. Every day the ...

  9. POJ - 3463 Sightseeing 最短路计数+次短路计数

    F - Sightseeing 传送门: POJ - 3463 分析 一句话题意:给你一个有向图,可能有重边,让你求从s到t最短路的条数,如果次短路的长度比最短路的长度多1,那么在加上次短路的条数. ...

随机推荐

  1. JSP页面字符集设置

    错误提示: HTTP Status 500 - /test1.jsp (line: 2, column: 1) Page directive must not have multiple occurr ...

  2. datatable中reload和load的区别

    ajax.reload()用于datatable表某个数据的变化而重新加载 ajax.url(url).load() 用于切换url时,datatable重新获取数据,加载.

  3. java-反射和代理

    1.类的编译和运行简易过程: java的源码文件(也称为编译单元,以.java为后缀的文件) ↓ 文件内最多只能有一个public修饰的类,否则编译器报错:某个类被public修饰,该类名必需与文件名 ...

  4. 【yii】【php】自定义故障代码

    实际状态码: 200 操作成功 406 账号密码错误 208 请勿重复操作 401 需登陆验证 405 不容许此方法 409 验证错误

  5. 生产-消费模式的synchronized和lock实现(十)

    lock: package com.net.thread.lock; import java.util.concurrent.locks.Condition; import java.util.con ...

  6. 硬盘安装Windows Server 2008(解决系统盘符变成D盘)

    硬盘安装Windows 2008系统方法 操作系统最好用的无疑是server 2003,但是现在Server 2003支持的软件越来越少,很多是故意不支持Server 2003了, 像php5.5以上 ...

  7. 读懂CCS链接命令文件(.cmd)

    链接器的核心工作就是符号表解析和重定位,链接命令文件则使得编程者可以给链接器提供必要的指导和辅助信息.多数时候,由于集成开发环境的存在,开发者无需了解链接命令文件的编写,使用默认配置即可.但若需要对计 ...

  8. Kotlin 二分法算法游戏--猜价格

    本人最新想学习算法,算法是提高程序性能的关键! 程序就是数据结构和算法! 写了一个二分法的游戏,供大家参考: 当然,语言基于kotlin import java.util.* /** * Create ...

  9. zedboard烧写SD卡启动linux镜像

    1. 先把SD卡格式化,然后把镜像文件拷贝到SD卡,下面应该是没有文件系统的 2. 插上SD卡,Zedboard设置启动模式,有5个跳线帽,配置如下,上电启动 3. 看下串口的输出

  10. laravel5.5入口文件分析

    入口文件 public/index.php 1.加载composer的自动加载器 require __DIR__.'/../vendor/autoload.php'; 自动加载,不用再各种requir ...