题意很简单,在仙人掌图上求两点的最短路。

做法:需要用到圆方树

先来看看什么是圆方树:圆方树,就是由仙人掌图转化而来,树上分两种点:圆点和方点,圆点是仙人掌图上的点,方点是由仙人掌的环转化而来。

由于仙人掌上的环不相交,圆方树的处理方法是对每一个环(每一个环都是点双连通分量)构建一个点,将这个环上的点接到这个方点上。这里盗一张名画:

虚线即原图边,红色的点即为方点。

一个显然的结论是任意一个方点唯一代表一个环,且整个图转成了一棵树。

(自然,转化为树后就可以使用一些处理树的问题的强大算法:如点分治,树链剖分等,但需要对方点特殊处理)

既然有边,边权如何赋值?:首先仙人掌图的遍历仍然依赖于 d f s dfs dfs算法,定义仙人掌图的 d f s dfs dfs树的父节点:从一棵仙人掌的根节点出发,对于不在环上的结点,它的父节点和树一般。对于每一个环,以最先遍历到的点为这个环的父节点。

环上的点连到方点的边权,就定义为该点到这个环的父节点的最短距离,显然方点到父节点的边权为0。(当然只是这题这样构造,也许在不同的题有不同的需求)

一个环有两个方向,需要走较短的那个方向,这就设计到对环的特殊处理。
来看建树的代码:

void solve(int rt,int u,int w) {top = 0;a[++top] = u;dep[top] = w;for(int i = u; i != rt; i = fa[i].fir)a[++top] = fa[i].fir,dep[top] = fa[i].sec;sz++;for(int i = 1; i <= top; i++)dep[i] += dep[i - 1];sum[sz] = dep[top];for(int i = 1; i <= top; i++) {ll z = min(dep[i],sum[sz] - dep[i]);add(a[i],sz + n,z);}
}
void tarjan(int u,int s) {dfn[u] = low[u] = ++cnt;for(auto it : g[u]) {if(it.fir == s) continue;if(!dfn[it.fir]) {fa[it.fir] = pii(u,it.sec);dis[it.fir] = dis[u] + it.sec;tarjan(it.fir,u);low[u] = min(low[u],low[it.fir]);if(low[it.fir] > dfn[u]) add(u,it.fir,it.sec);} else {low[u] = min(low[u],dfn[it.fir]);}}for(auto it : g[u]) {if(it.fir == s) continue;if(dfn[it.fir] > dfn[u] && fa[it.fir].fir != u) solve(u,it.fir,it.sec);}
}

由于要找到所有的环,每一个环都是一个点双,可以用tarjan算法。
(仙人掌图等价于多个环的基环树,环的处理方式可以一样,tarjan算法也可以应用于基环树中,不过由于基环树只有一个环,可以使用更简单的方法)

和仙人掌图 d p dp dp 的方式一样,先加非环上的边,环最后来处理。

找环的代码,原理很简单,一个环在 d f s dfs dfs树上一定有一条返祖边,if里的条件相当于在找那条返祖边。

画个图理解,对于每个环,只要找那条红色的返祖边,就可以唯一确定一个环。在仙人掌图上,返祖边一定是一个环的父节点,指向一个环的最低的结点(这里的最低只最后访问),这样处理很方便。

找到环后,就需要对环进行特殊处理,这里只是为了建图,如果是仙人掌dp,处理方式和基环树相同,需要对环形dp 进行处理(如最大独立集,仙人掌直径等)

s o l v e solve solve函数就是对环处理的函数:
将环展开,依次向方点加边即可,由于这道题求的是最短路,需要用数组记录一个环的边权和。

构建好树后,变成求树上最短路,由于树上路径唯一,只需要倍增找lca 即可。

一个问题是倍增找到的lca ,可能是圆点也可能是方点。

如果lca是圆点:没有问题,直接计算答案即可。

如果lca是方点:方点并不是原图的点,圆方树每一个方点都代表一个圆,这代表询问点对的祖先在一个环上,需要计算这两个祖先节点的距离,根据倍增的算法原理,最后一次跳到的点就是这两个结点。由于环有两个方向,取较小的方向即可。


代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
typedef long long ll;
#define pii pair<int,int>
#define pll pair<ll,ll>
#define fir first
#define sec second
const int mx = 20;
int dfn[maxn],low[maxn],cnt,sz;
vector<pii> g[maxn];
vector<pll> h[maxn];
pii fa[maxn];
int n,q,m;
ll d[maxn],dis[maxn],sum[maxn];
ll dep[maxn],a[maxn],top = 0;
ll p[maxn][mx + 1],gw[maxn][mx + 1];
void add(int u,int v,ll w) {h[u].push_back(pll(v,w));h[v].push_back(pll(u,w));
}
void solve(int rt,int u,int w) {top = 0;a[++top] = u;dep[top] = w;for(int i = u; i != rt; i = fa[i].fir)a[++top] = fa[i].fir,dep[top] = fa[i].sec;sz++;for(int i = 1; i <= top; i++)dep[i] += dep[i - 1];sum[sz] = dep[top];for(int i = 1; i <= top; i++) {ll z = min(dep[i],sum[sz] - dep[i]);add(a[i],sz + n,z);}
}
void tarjan(int u,int s) {dfn[u] = low[u] = ++cnt;for(auto it : g[u]) {if(it.fir == s) continue;if(!dfn[it.fir]) {fa[it.fir] = pii(u,it.sec);dis[it.fir] = dis[u] + it.sec;tarjan(it.fir,u);low[u] = min(low[u],low[it.fir]);if(low[it.fir] > dfn[u]) add(u,it.fir,it.sec);} else {low[u] = min(low[u],dfn[it.fir]);}}for(auto it : g[u]) {if(it.fir == s) continue;if(dfn[it.fir] > dfn[u] && fa[it.fir].fir != u) solve(u,it.fir,it.sec);}
}
void prework(int u,int s,int w) {for(int i = 1; i <= mx; i++) {p[u][i] = p[p[u][i - 1]][i - 1];gw[u][i] = gw[u][i - 1] + gw[p[u][i - 1]][i - 1];}for(auto it : h[u]) {if(it.fir == s) continue;d[it.fir] = d[u] + 1;p[it.fir][0] = u;gw[it.fir][0] = it.sec;prework(it.fir,u,it.sec);}
}
ll qry(int x,int y) {ll ans = 0;if(d[x] < d[y]) swap(x,y);for(int i = mx; i >= 0; i--) {if(d[p[x][i]] >= d[y]) {ans += gw[x][i];x = p[x][i];}}for(int i = mx; i >= 0; i--) {if(p[x][i] != p[y][i]) {ans += gw[x][i];ans += gw[y][i];x = p[x][i],y = p[y][i];}}if(x == y) return ans;else if(p[x][0] > n) {int rt = p[x][0];ll d = abs(dis[x] - dis[y]);ans += min(d,sum[rt - n] - d);return ans;} else return ans + gw[x][0] + gw[y][0];
}
int main() {scanf("%d%d%d",&n,&m,&q);for(int i = 1; i <= m; i++) {int u,v,w;scanf("%d%d%d",&u,&v,&w);g[u].push_back(pii(v,w));g[v].push_back(pii(u,w));} tarjan(1,0);d[1] = 1;prework(1,0,0);for(int i = 1; i <= q; i++) {int u,v;scanf("%d%d",&u,&v);printf("%lld\n",qry(u,v));}return 0;
}

洛谷 :P5236 【模板】静态仙人掌(圆方树模板 + 仙人掌最短路)相关推荐

  1. P5236 【模板】静态仙人掌(仙人掌圆方树)

    无向仙人掌图 一般需要重构成 仙人掌有向树 然后我们 就考虑 圆点的 方点的不同讨论 这个题是查询两点间最短路 如果lca 是圆点 那么就是 d[a]+d[b]-2*d[lca] 如果是方点 我们需要 ...

  2. 仙人掌圆方树学习笔记

    终于对仙人掌有了一点初步的理解. 仙人掌 仙人掌是什么? 仙人掌是一个无向图. 仙人掌有什么特点? 仙人掌的每条边只属于一个简单环. 下面是一个栗子 有什么用呢? 我们可以先用\(tarjan\)找出 ...

  3. cactus仙人掌图【仙人掌圆方树+树形DP+单调队列】

    题目链接 BZOJ 1023 首先,圆方树是比较好想到的,维护直径,我们最方便的做法就是先让它变成一棵树,这里因为是仙人掌图,所以就用圆方树来构建. 再者,就是维护直径了,比较好想到的是非环上结点,就 ...

  4. 仙人掌问题(圆方树)

    [算法简介] 仙人掌就是把树上多连了一些返祖边,构成了一些环 根据仙人掌这个名字我们也可以较为形象的感受到图的形态 具体的,仙人掌分为点仙人掌和边仙人掌,定义分别为点/边最多属于一个环 之所以把这样的 ...

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

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

  6. 道路相遇【一般图的圆方树-广义圆方树】

    题目链接 刚开始拿到这道题的时候,先写了Tarjan缩点构树,没过样例,但是先把40分拿到了. 然后再想,就如同样例给出的那样,我们所定义的原点和方点,实际上在Tarjan直接缩点上并不能起到直接体现 ...

  7. 【luogu P4320】道路相遇(圆方树)

    道路相遇 题目链接:luogu P4320 题目大意 给你一个无向连通图,无重边自环,然后每次给你两点,问你有多少个点是两点间路径必有的. 思路 圆方树pre模板题? 圆方树怎么做这里不说,看铁人两项 ...

  8. 仙人掌与圆方树的学习 【模板】静态仙人掌

    题目链接 BZOJ 2125 最短路 圆方树 求一幅仙人掌图中,Q次询问两点最短路. 仙人掌问题,我们可以直接将原来的N个点缩点成为一棵生成树--圆方树. 这棵圆方树是怎样建立的呢,首先,我们看图: ...

  9. 洛谷P4630 [APIO2018] Duathlon 铁人两项 【圆方树】

    题目链接 洛谷P4630 题解 看了一下部分分,觉得树的部分很可做,就相当于求一个点对路径长之和的东西,考虑一下能不能转化到一般图来? 一般图要转为树,就使用圆方树呗 思考一下发现,两点之间经过的点双 ...

最新文章

  1. 上海交大张拳石:漂在零丁洋里的体系,神经网络的博弈交互解释性
  2. KubeEdge向左,K3S向右
  3. MySQL 数据库 InnoDB 和 MyISAM 数据引擎的差别
  4. 研究生 论文写作【要注意的30个禁忌(总体问题、选题方面、摘要方面、研究方法方面、讨论与结果、结论方面)】
  5. TCP UDP HTTP 的关系和区别
  6. 约束布局constraint-layout导入失败的解决方案 - 转
  7. 程序员面试金典 - 面试题 08.13. 堆箱子(DP)
  8. 推荐几款好用的模态框附带教程
  9. 对HTTPCONNECTION的理解
  10. 5岁自学python编程-python学习笔记(五岁以下儿童)深深浅浅的副本复印件,文件和文件夹...
  11. vs 执行单个文件,如cpp
  12. 如何卸载冰点还原精灵
  13. 科比:你知道洛杉矶每天早上四点钟是什么样子吗?
  14. 云计算(Day 8)
  15. java 计算经度纬度之间的距离
  16. AT指令(中文详解版)(二)
  17. HPRD数据库HPRD_Release9_062910表中最后一列RefSeq字段的含义
  18. 视频教程-ADAS/HAD软件架构-嵌入式
  19. 使用navicat连接远程linux mysql数据库出现10061
  20. 在线购物系统——顺序图

热门文章

  1. 鸿蒙平板好用吗,能装“APP”的手表?华为鸿蒙手表平板来了!这钱要不要花?...
  2. android 流畅动画svg,Android自定义View-SVG动画
  3. python bitmap_Python win32ui.CreateBitmap方法代码示例
  4. 跨平台应用开发进阶(四十二)vue与nvue页面设计方案探究
  5. Tendermint-2-共识算法:Tendermint-BFT详解
  6. 红蓝对抗模拟演练系统软件解决方案
  7. 基于axios前后端数据交互
  8. POI之Word转化为Html-yellowcong
  9. 抱一鸿蒙超然之志,第29章 鸿蒙开启 逍遥隐退 天机入世
  10. react 根据获取的时间,实现时间按秒更新