bzoj2125 最短路——仙人掌两点间距离
题目: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 最短路——仙人掌两点间距离的更多相关文章
- BZOJ2125 最短路 【仙人掌最短路】
题目 给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径. 输入格式 输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个整数v,u,w表示一 ...
- [BZOJ2125]最短路(圆方树DP)
题意:仙人掌图最短路. 算法:圆方树DP,$O(n\log n+Q\log n)$ 首先建出仙人掌圆方树(与点双圆方树的区别在于直接连割边,也就是存在圆圆边),然后考虑点u-v的最短路径,显然就是:在 ...
- bzoj2125 最短路
Description 给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径. Input 输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个 ...
- BZOJ2125 最短路 圆方树、倍增
传送门 对仙人掌建立圆方树,然后对边定权 对于圆点和圆点之间的边,是原来仙人掌上的桥,边权保持不变 对于圆点和方点之间的边,将圆方树看做以一个圆点为根的有根树之后,一个方点的父亲一定是一个圆点.对于这 ...
- BZOJ.2125.最短路(仙人掌 最短路Dijkstra)
题目链接 多次询问求仙人掌上两点间的最短路径. 如果是在树上,那么求LCA就可以了. 先做着,看看能不能把它弄成树. 把仙人掌看作一个图(实际上就是),求一遍根节点到每个点的最短路dis[i]. 对于 ...
- 2018.07.25 bzoj2125: 最短路(圆方树+倍增)
传送门 人生的第一道仙人掌. 这道题求是仙人掌上的最短路. 先建出圆方树,然后用倍增跑最短路,当lca" role="presentation" style=" ...
- [BZOJ2125]最短路[圆方树]
题意 给定仙人掌,多次询问两点之间的最短路径. \(n\le 10000, Q\le 10000\) 分析 建出圆方树,分路径 lca 是圆点还是方点讨论. 预处理出根圆点到每个圆点的最短距离 \( ...
- 【题解】Bzoj2125最短路
处理仙人掌 ---> 首先建立出圆方树.则如果询问的两点 \(lca\) 为圆点,直接计算即可, 若 \(lca\) 为方点,则需要额外判断是走环的哪一侧(此时与两个点在环上的相对位置有关.) ...
- bzoj 2125 最短路——仙人掌两点间最短路
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2125 因为看了TJ又抄了标程,现在感觉还是轻飘飘的……必须再做一遍. 两点间的情况: 1.直 ...
随机推荐
- vue组件---动态组件&异步组件
(1)在动态组件上使用keep-alive 之前曾经在一个多标签的界面中使用 is 特性来切换不同的组件.接下来简单回顾下 <component>元素是vue 里面的一个内置组件.在里面使 ...
- 10Java Server Pages 隐式对象
Java Server Pages 隐式对象 JSP隐式对象是Web容器加载的一组类的实例,它不像一般的Java对象那样用“new”去获取实例,而是可以直接在JSP页面使用的对象.JSP提供的隐式对象 ...
- oracle_backup
#!/bin/bash DAYS=`date +"%Y%m%d"` . /home/oracle/.bash_profile # /home/opt/oracle/11g/bin/ ...
- tab下拉显示
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...
- Luogu P3797 妖梦斩木棒
解题思路 用线段树做这个就不用说了吧,但是要维护的东西确实很神奇.在每一个节点上都维护一个$lbkt$,表示这个区间上最靠左的右括号的位置:一个$rbkt$,表示这个区间上最靠右的左括号的位置.还有一 ...
- led1,1s取反,led2计数10次取反
1 //利用定时器0 1s,led1取反,利用计数器1,跳10,取反 #include<reg52.h> #define uchar unsigned char #define uint ...
- 【模板】大数乘法(51nod 1027)
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long #defin ...
- Hdu 4864(Task 贪心)(Java实现)
Hdu 4864(Task 贪心) 原题链接 题意:给定n台机器和m个任务,任务和机器都有工作时间值和工作等级值,一个机器只能执行一个任务,且执行任务的条件位机器的两个值都大于等于任务的值,每完成一个 ...
- Codeforces 989C - A Mist of Florescence
传送门:http://codeforces.com/contest/989/problem/C 这是一个构造问题. 构造一张网格,网格中的字符为’A’.’B’.’C’.’D’,并且其连通块的个数分别为 ...
- JS权威指南笔记1
1.JavaScript数据类型可分为两种:原始类型和对象类型.原始类型下又包括数字.字符串和布尔值,以及null和undefined这两个特殊的:对象是属性的集合,且每个属性都有自己的"名 ...