题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2125

仙人掌!模仿 lyd 的代码写的,也算是努力理解了;

主要分成 lca 在环上和不在环上,先缩环(环上的点直接连向最高点),那么不在环上的 lca 就跟在树上一样求法;

在环上的话就先求出环外部分,再计算环内距离;

所以一遍 spfa 求从根出发的最短路,再一遍 dfs 求 dfs 序的 dis ,用来处理环上距离,然后 bfs 计算深度用来倍增求 lca,然后分类求答案即可;

注意边数就是点的4倍,还要算上缩环时连的边。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
int const maxn=,maxm=;//
int n,m,Q,hd[maxn],ct=,dis[maxn],dist[maxn],cr,col[maxn],tim,dfn[maxn];
int fa[maxn],len[maxn],f[maxn][],dep[maxn];
bool del[maxm],vis[maxn];
queue<int>q;
struct N{
int to,nxt,w;
N(int t=,int n=,int w=):to(t),nxt(n),w(w) {}
}ed[maxm];
void add(int x,int y,int z){ed[++ct]=N(y,hd[x],z); hd[x]=ct;}
int ab(int x){return x<?-x:x;}
void spfa()
{
memset(dist,0x3f,sizeof dist);
memset(vis,,sizeof vis);
dist[]=; q.push(); vis[]=;
while(q.size())
{
int x=q.front(); q.pop(); vis[x]=;
for(int i=hd[x],u;i;i=ed[i].nxt)
if(dist[u=ed[i].to]>dist[x]+ed[i].w)
{
dist[u]=dist[x]+ed[i].w;
if(!vis[u])vis[u]=,q.push(u);
}
}
}
void make(int x,int e)
{
int i,y=x; x=ed[e].to;
len[++cr]+=ed[e].w; col[y]=cr; del[e]=del[e^]=;
add(x,y,); add(y,x,);//!连向最高点
for(i=fa[y];(y=ed[i^].to)!=x;i=fa[y])
{
len[cr]+=ed[i].w; col[y]=cr;
del[i]=del[i^]=;
add(x,y,); add(y,x,);//!连向最高点
}
col[x]=cr; len[cr]+=ed[i].w;
}
void dfs(int x)
{
dfn[x]=++tim;
for(int i=hd[x],u;i;i=ed[i].nxt)
{
if(!dfn[u=ed[i].to])
{
fa[u]=i; dis[u]=dis[x]+ed[i].w;
dfs(u);
}
else if(dfn[u]<dfn[x]&&fa[x]!=(i^))make(x,i);
}
}
void bfs()
{
while(q.size())q.pop();
memset(vis,,sizeof vis);
vis[]=; q.push(); dep[]=;
while(q.size())
{
int x=q.front(); q.pop();
for(int i=hd[x],u;i;i=ed[i].nxt)
{
if(vis[u=ed[i].to]||del[i])continue;
vis[u]=; dep[u]=dep[x]+; f[u][]=x;
for(int j=;j<=;j++)f[u][j]=f[f[u][j-]][j-];
q.push(u);
}
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
int a=x,b=y;
int k=dep[x]-dep[y];
for(int i=;i<=;i++)
if(k&(<<i))x=f[x][i];
if(x==y)return dist[a]-dist[b];
for(int i=;i>=;i--)
if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
if(col[x]&&col[x]==col[y])
{
int l=ab(dis[x]-dis[y]);
return dist[a]-dist[x]+dist[b]-dist[y]+min(l,len[col[x]]-l);
//两个点从环外跳到环上,所以先加上环外部分的 dist,再算环上的最短距离
}
return dist[a]+dist[b]-*dist[f[x][]];
}
int main()
{
scanf("%d%d%d",&n,&m,&Q);
for(int i=,x,y,z;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z); add(y,x,z);
}
spfa();
dfs();
bfs();
for(int i=,x,y;i<=Q;i++)
{
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));
}
}

bzoj2125 最短路——仙人掌两点间距离的更多相关文章

  1. BZOJ2125 最短路 【仙人掌最短路】

    题目 给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径. 输入格式 输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个整数v,u,w表示一 ...

  2. [BZOJ2125]最短路(圆方树DP)

    题意:仙人掌图最短路. 算法:圆方树DP,$O(n\log n+Q\log n)$ 首先建出仙人掌圆方树(与点双圆方树的区别在于直接连割边,也就是存在圆圆边),然后考虑点u-v的最短路径,显然就是:在 ...

  3. bzoj2125 最短路

    Description 给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径. Input 输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个 ...

  4. BZOJ2125 最短路 圆方树、倍增

    传送门 对仙人掌建立圆方树,然后对边定权 对于圆点和圆点之间的边,是原来仙人掌上的桥,边权保持不变 对于圆点和方点之间的边,将圆方树看做以一个圆点为根的有根树之后,一个方点的父亲一定是一个圆点.对于这 ...

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

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

  6. 2018.07.25 bzoj2125: 最短路(圆方树+倍增)

    传送门 人生的第一道仙人掌. 这道题求是仙人掌上的最短路. 先建出圆方树,然后用倍增跑最短路,当lca" role="presentation" style=" ...

  7. [BZOJ2125]最短路[圆方树]

    题意 给定仙人掌,多次询问两点之间的最短路径. \(n\le 10000, Q\le 10000​\) 分析 建出圆方树,分路径 lca 是圆点还是方点讨论. 预处理出根圆点到每个圆点的最短距离 \( ...

  8. 【题解】Bzoj2125最短路

    处理仙人掌 ---> 首先建立出圆方树.则如果询问的两点 \(lca\) 为圆点,直接计算即可, 若 \(lca\) 为方点,则需要额外判断是走环的哪一侧(此时与两个点在环上的相对位置有关.) ...

  9. bzoj 2125 最短路——仙人掌两点间最短路

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2125 因为看了TJ又抄了标程,现在感觉还是轻飘飘的……必须再做一遍. 两点间的情况: 1.直 ...

随机推荐

  1. java_线程创建的两种方法

    线程创建的方法有两种: 一 继承Thread类: public class ThreadTest { public static void main(String[] args) { //4)在mai ...

  2. 04Servlet的生命周期

    Servlet的生命周期 Servlet运行在Servlet容器中,其生命周期由容器来管理.Servlet的生命周期通过javax.servlet.Servlet接口中的init().service( ...

  3. node事件循环和消息队列简单分析

    node的好处毋庸置疑,事件驱动,异步非阻塞I/O,以及处理高并发的能力深入人心,因此大家喜欢用node做一些小型后台服务或者作为中间层和其他服务配合完成一些大型应用场景. 什么是异步? 异步和同步应 ...

  4. TWaver3D特效系列之环境映射

    随着TWaver3D的快速发展,越来越多的各种功能都在不断加强,包括性能的极大提升(可以参考这里),3D编辑器的易用性和功能持续增强(欢迎大家申请试用),各种特效的增加,特效是本文的主角. 对于UI技 ...

  5. 每日命令:(4)mkdir

    linux mkdir 命令用来创建指定的名称的目录,要求创建目录的用户在当前目录中具有写权限,并且指定的目录名不能是当前目录中已有的目录. 1.命令格式: mkdir [选项] 目录... 2.命令 ...

  6. docker-ce安装官翻

    参考http://www.cnblogs.com/maple42/p/5868846.htmlhttp://blog.csdn.net/lizehua123/article/details/50601 ...

  7. linux free命令-显示内存的使用情况

    更多Linux 性能监测与优化 关注 Linux命令大全 free命令可以显示当前系统未使用的和已使用的内存数目,还可以显示被内核使用的内存缓冲区. 语法 free(选项) 选项 -b:以Byte为单 ...

  8. git命令大杂烩

    查看版本库中的文件: git ls-files添加到暂存区: git add filesName|\folderName(循环递归) git add .(添加当前目录下的所有文件包括子目录,如果添加文 ...

  9. 重载与重写的区别----https://blog.csdn.net/zhu_apollo/article/details/1852542

    重载 overloading        1) 方法重载是让类以统一的方式处理不同类型数据的一种手段.多个同名函数同时存在,具有不同的参数个数/类型.重载是一个类中多态性的一种表现.        ...

  10. How to put username &password in MongoDB(Security&Authentication)?(配置用户认证在MongoDB)

    Default do not need username and password authenticate when access mongoDB ,I want to set up the use ...