【BZOJ】2125: 最短路 圆方树(静态仙人掌)
【题意】给定带边权仙人掌图,Q次询问两点间最短距离。n,m,Q<=10000
【算法】圆方树处理仙人掌问题
【题解】树上的两点间最短路问题,常用倍增求LCA解决,考虑扩展到仙人掌图。
先对仙人掌图建圆方树,圆圆边和原图边权一致。对于每个方点代表的环,记深度最小的点为x,则圆方边的边权是圆点到x的最短距离。
若lca(u,v)为圆点,则两点间最短路转化为圆方树上dis[u]+dis[v]-2*dis[lca]。(向上延伸的路径,经过环则必然经过每个方点的x,计算无误)
若lca(u,v)为方点,则记u,v在方点连接的圆点A,B的子树内,那么两点间最短路为dis[u]+dis[v]-dis[A]-dis[B]+dis(A,B),dis(A,B)是A,B在环上的短侧路径。
复杂度O(Q log n)。
实现细节:
1.Tarjan:建圆方树(先处理树边,最后在深度最小处处理环)
2.处理方点:s[i]表示点i从所在环点x(深度最小)开始逆时针的距离,最终s[x]记为s[N]后s[x]=0。另外注意要记录一下环中点的编号顺序。
3.LCA:圆点直接计算,方点中dis(A,B)=min{ s[A]+s[w]-s[B] , s[B]-s[A] }(A在B的顺时针方向,否则交换AB)。
4.注意防止访问父亲的边是i^1,初始tot=1。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=;
int N,fa[maxn],b[maxn],f[maxn][],dfn[maxn],low[maxn],dfsnum=,deep[maxn],A,B,n,m,id[maxn];
ll s[maxn],dis[maxn];
struct tu{
int first[maxn],tot;
struct edge{int v,w,from;}e[maxn*];
void insert(int u,int v,int w){
tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;
tot++;e[tot].v=u;e[tot].w=w;e[tot].from=first[v];first[v]=tot;
}
}G;
int first[maxn],tot;
struct edge{int v,w,from;}e[maxn*];
void insert(int u,int v,int w){
tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;
tot++;e[tot].v=u;e[tot].w=w;e[tot].from=first[v];first[v]=tot;
}
void solve(int u,int v,int w){
N++;
int pre=w,ID=;
for(int i=v;i!=fa[u];i=fa[i]){
s[i]=pre;
pre+=b[i];
id[i]=ID++;
}
s[N]=s[u];s[u]=;
for(int i=v;i!=fa[u];i=fa[i])insert(N,i,min(s[i],s[N]-s[i]));
}
void tarjan(int x,int father){
dfn[x]=low[x]=++dfsnum;
for(int i=G.first[x];i;i=G.e[i].from)if(i!=father){
int y=G.e[i].v;
if(!dfn[y]){
fa[y]=x;b[y]=G.e[i].w;
tarjan(G.e[i].v,i^);
low[x]=min(low[x],low[y]);
}else low[x]=min(low[x],dfn[y]);
if(low[y]>dfn[x])insert(x,y,G.e[i].w);
}
for(int i=G.first[x];i;i=G.e[i].from){
int y=G.e[i].v;
if(fa[y]!=x&&dfn[y]>dfn[x])solve(x,y,G.e[i].w);
}
}
void dfs(int x,int father){
for(int j=;(<<j)<=deep[x];j++)f[x][j]=f[f[x][j-]][j-];
for(int i=first[x];i;i=e[i].from)if(i!=father){
f[e[i].v][]=x;
deep[e[i].v]=deep[x]+;
dis[e[i].v]=dis[x]+e[i].w;
dfs(e[i].v,i^);
}
}
int lca(int x,int y){
if(deep[x]<deep[y])swap(x,y);
int d=deep[x]-deep[y];
for(int i=;(<<i)<=d;i++)if(d&(<<i))x=f[x][i];
if(x==y)return x;
for(int i=;i>=;i--)if((<<i)<=deep[x]&&f[x][i]!=f[y][i]){
x=f[x][i];y=f[y][i];
}
A=x;B=y;
return f[x][];
} int main(){
int Q;
scanf("%d%d%d",&n,&m,&Q);
int u,v,w;
G.tot=;tot=;
for(int i=;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
G.insert(u,v,w);
}
N=n;tarjan(,);dfs(,);
while(Q--){
scanf("%d%d",&u,&v);
w=lca(u,v);
if(w<=n)printf("%lld\n",dis[u]+dis[v]-*dis[w]);
else{
ll ans=dis[u]+dis[v]-dis[A]-dis[B];
if(id[A]<id[B])ans+=min(s[A]+s[w]-s[B],s[B]-s[A]);
else ans+=min(s[B]+s[w]-s[A],s[A]-s[B]);
printf("%lld\n",ans);
}
}
return ;
}
【BZOJ】2125: 最短路 圆方树(静态仙人掌)的更多相关文章
- 图论杂项细节梳理&模板(虚树,圆方树,仙人掌,欧拉路径,还有。。。)
orzYCB 虚树 %自为风月马前卒巨佬% 用于优化一类树形DP问题. 当状态转移只和树中的某些关键点有关的时候,我们把这些点和它们两两之间的LCA弄出来,以点的祖孙关系连成一棵新的树,这就是虚树. ...
- BZOJ2125 最短路 圆方树、倍增
传送门 对仙人掌建立圆方树,然后对边定权 对于圆点和圆点之间的边,是原来仙人掌上的桥,边权保持不变 对于圆点和方点之间的边,将圆方树看做以一个圆点为根的有根树之后,一个方点的父亲一定是一个圆点.对于这 ...
- [BZOJ2125]最短路(圆方树DP)
题意:仙人掌图最短路. 算法:圆方树DP,$O(n\log n+Q\log n)$ 首先建出仙人掌圆方树(与点双圆方树的区别在于直接连割边,也就是存在圆圆边),然后考虑点u-v的最短路径,显然就是:在 ...
- [BZOJ2125]最短路[圆方树]
题意 给定仙人掌,多次询问两点之间的最短路径. \(n\le 10000, Q\le 10000\) 分析 建出圆方树,分路径 lca 是圆点还是方点讨论. 预处理出根圆点到每个圆点的最短距离 \( ...
- 圆方树总结 [uoj30]Tourists
圆方树总结 所谓圆方树就是把一张图变成一棵树. 怎么变啊qaq 这里盗一张图 简单来说就是给每一个点双新建一个点,然后连向这个点双中的每一个点.特殊的,把两个点互相连通的也视作一个点双. 我们把原来就 ...
- bzoj 2125 最短路 点双 圆方树
LINK:最短路 一张仙人掌图 求图中两点最短路. \(n<=10000,Q<=10000,w>=1\) 考虑边数是多少 m>=n-1 对于一张仙人掌图 考虑先构建出来dfs树 ...
- BZOJ.2125.最短路(仙人掌 圆方树)
题目链接 圆方树.做题思路不写了.. 就是当LCA是方点时跳进那个环可以分类讨论一下用树剖而不必须用倍增: 如果v是u的(唯一的那个)重儿子,那么u的DFS序上+1的点即是要找的:否则v会引出一条新的 ...
- 【BZOJ2125】最短路(仙人掌,圆方树)
[BZOJ2125]最短路(仙人掌,圆方树) 题面 BZOJ 求仙人掌上两点间的最短路 题解 终于要构建圆方树啦 首先构建出圆方树,因为是仙人掌,和一般图可以稍微的不一样 直接\(tarjan\)缩点 ...
- 2018.07.25 bzoj2125: 最短路(圆方树+倍增)
传送门 人生的第一道仙人掌. 这道题求是仙人掌上的最短路. 先建出圆方树,然后用倍增跑最短路,当lca" role="presentation" style=" ...
随机推荐
- 求最大子串和以及其中一个子串(java)
public static void getMaxSum(int[] a){ int max = a[0]; int sum = a[0]; int temp = 0; int start = 0; ...
- Java 成员初始化顺序
package com.cwcec.test; class Fu { int num = 5; //构造代码块 { System.out.println("Fu constructor co ...
- IOC 依赖注入 Unity
http://kb.cnblogs.com/page/115333/ http://www.bianceng.cn/Programming/net/201007/18255.htm http://bl ...
- Java的一些细节问题
一.Java求余%的结果符号取决于除数的符号位:小数也可以求余,余数仍为小数. package com.test; public class Test { /** * @author 容杰龙 */ p ...
- 蜗牛慢慢爬 LeetCode 1.Two Sum [Difficulty: Easy]
题目 Given an array of integers, return indices of the two numbers such that they add up to a specific ...
- 【final】评价①
飞天小女警添加猜你喜欢功能,个人很喜欢.当推荐产品不喜欢的时候还有其他的选择,很人性化. 金州勇士将管理人员的角色分开,使整个系统的分工更明确,也更清晰. 新蜂的俄罗斯方块随着等级的提升有直观的颜色变 ...
- PAT 甲级 1027 Colors in Mars
https://pintia.cn/problem-sets/994805342720868352/problems/994805470349344768 People in Mars represe ...
- 利用C#进行文件读写的方法选择总结
小的文本文件(100M以下)直接用File类的ReadAllText()和WriteAllText()方法 这两个方法内部其实就是封装了StreamReader类的ReadToEnd()和Stream ...
- WCF跨时区自动转换问题
背景:api端 用wcf做的 客户端是silverlight, 服务和消费 不是同一个时区 状况:客户端调用返回对象有个字段是datetime ,返回的时间和数据库相差好几个小时,找了很久,最后把da ...
- 第73天:jQuery基本动画总结
一.DOM对象跟jQuery对象相互转换 jQuery对象转换成DOM对象: 方式一:$(“#btn”)[0] 方式二:$(“#btn”).get(0) DOM对象转换成jQuery对象: $(doc ...