2125: 最短路

Time Limit: 1 Sec  Memory Limit: 259 MB
Submit: 1873  Solved: 754
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Sample Input

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

Sample Output

5
6

什么是圆方树:

对于一棵仙人掌

  • 仙人掌的所有点 → 圆方树中的所有圆点
  • 仙人掌的所有不在环中的边 → 连接圆方树中两个圆点的边
  • 仙人掌中的其中一个环 →  圆方树中的其中一个方点, 这个方点向当前环中的所有圆点连边,边的长度 = 这个点到这个环中最接近根的那个点的距离

一张非常形象的图,来自于一个课件

其实看了这个图应该就什么都懂了,一些性质也很容易被发现

仙人掌两点的最短路:

先建立出圆方树,关于如何建立圆方树:双联通分量

之后将问题转化成圆方树的LCA,LCA可以用树链剖分解决

考虑求LCA的两种情况:

  1. 如果两点的LCA是圆点:可以证明仙人掌树上的最短路 = 圆方树上的最短路
  2. 如果两点的LCA是方点:说明这两点会在环上相遇,先求出这两点到环的距离,然后在环上分类讨论下就可以了

搞定

剩下的代码中有注释

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
typedef struct Road
{int v;int len;
}Road;
Road now;
vector<Road> G[20005], T[20005];
int n, t, cnt, Time[20005], low[20005], tp[20005], dep[20005], fa[20005], a[20005], dis[20005];
struct RST
{int fa[20005], size[20005], hson[20005], top[20005], dep[20005], dis[20005];int t, rak[20005], id[20005], cir[20005], zn[20005];void Sech1(int u, int p)       //对树先来一套基本操作,顺便求出每个节点的重儿子{int v, i;fa[u] = p, dep[u] = dep[p]+1;size[u] = 1;for(i=0;i<T[u].size();i++){v = T[u][i].v;if(v==p)continue;dis[v] = dis[u]+T[u][i].len;Sech1(v, u);size[u] += size[v];if(size[v]>size[hson[u]])hson[u] = v;}}void Sech2(int u, int p)            //重链剖分{int i, v;top[u] = p;rak[u] = ++t, id[t] = u;if(hson[u])Sech2(hson[u], p);for(i=0;i<T[u].size();i++){v = T[u][i].v;if(v==fa[u] || v==hson[u])continue;Sech2(v, v);}}int LCA(int u, int v){while(top[u]^top[v]){if(dep[top[u]]<dep[top[v]])v = fa[top[v]];elseu = fa[top[u]];}if(dep[u]<dep[v])return u;return v;}int Jump(int u, int lca)     //跳到lca的那个环上{int ret;while(top[u]!=top[lca])ret = top[u], u = fa[top[u]];if(u==lca)            //如果lca正好是一条链的尾端,那么上一个链的链头肯定就是当前要求的点return ret;return id[rak[lca]+1];       //如果lca不在链的尾端,那么当前要求的点一定是lca的重儿子!要不怎么会在一条链上}int Query(int u, int v){int lca, A, B, d1, d2;lca = LCA(u, v);if(lca<=n)     //如果LCA是圆点,说明他们不在环上相遇,直接返回它们与lca的距离即可return dis[u]+dis[v]-2*dis[lca];else        //在环上相遇{A = Jump(u, lca), B = Jump(v, lca);d1 = dis[A]-dis[lca], d2 = dis[B]-dis[lca];if(zn[A]==0)d1 = cir[lca]-d1;if(zn[B]==0)d2 = cir[lca]-d2;      //d1和d2分别表示A和B离当前环中最接近根的那个点的距离return dis[u]-dis[A]+dis[v]-dis[B]+min(abs(d1-d2),cir[lca]-abs(d1-d2));}}
}RST;
void CreateS(int u, int v, int len)
{int R, sum, i, D;D = R = 0, sum = len, cnt++;     //cnt为当前新建的方点for(i=v;1;i=fa[i]){a[++R] = i;if(i==u)break;sum += dis[i]-dis[fa[i]];}for(i=1;i<=R/2;i++)swap(a[i], a[R-i+1]);RST.cir[cnt] = sum;for(i=1;i<=R;i++){now.len = min(D, sum-D);now.v = a[i], T[cnt].push_back(now);now.v = cnt, T[a[i]].push_back(now);RST.zn[a[i]] = (now.len==D);D += dis[a[i+1]]-dis[a[i]];}
}
void Tarjan(int u, int p)
{int i, v;Time[u] = low[u] = ++t;fa[u] = p, dep[u] = dep[p]+1;for(i=0;i<G[u].size();i++){v = G[u][i].v;if(v==p)continue;if(Time[v]==0){dis[v] = dis[u]+G[u][i].len;Tarjan(v, u);low[u] = min(low[u], low[v]);}elselow[u] = min(low[u], Time[v]);if(low[v]>Time[u]){T[u].push_back(G[u][i]);now.v = u, now.len = G[u][i].len;T[v].push_back(now);}}for(i=0;i<G[u].size();i++){v = G[u][i].v;if(fa[v]!=u && Time[v]>Time[u])CreateS(u, v, G[u][i].len);}
}
int main(void)
{int i, m, T, x, y;scanf("%d%d%d", &n, &m, &T), cnt = n;for(i=1;i<=m;++i){scanf("%d%d%d", &x, &y, &now.len);now.v = y, G[x].push_back(now);now.v = x, G[y].push_back(now);}Tarjan(1, 0);RST.Sech1(1, 0);RST.Sech2(1, 1);while(T--){scanf("%d%d", &x, &y);printf("%d\n", RST.Query(x, y));}return 0;
}
/*
15 18 0
10 15 15 9 9 14 14 2
10 13 13 12 12 11 11 10 10 9 9 2
3 8 8 7 7 6 6 5 5 4 4 3 3 2 2 1
*/

圆方树(bzoj 2125: 最短路)相关推荐

  1. 洛谷 :P5236 【模板】静态仙人掌(圆方树模板 + 仙人掌最短路)

    题意很简单,在仙人掌图上求两点的最短路. 做法:需要用到圆方树 先来看看什么是圆方树:圆方树,就是由仙人掌图转化而来,树上分两种点:圆点和方点,圆点是仙人掌图上的点,方点是由仙人掌的环转化而来. 由于 ...

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

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

  3. bzoj#2125. 最短路

    bzoj#2125. 最短路 题目描述 Description 给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径. Input 输入的第一行包含三个整数 ...

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

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

  5. 【知识小结】圆方树 广义圆方树

    关于仙人掌的总结 immortalCO的博客 yyb的博客 模板 namespace T{vector <int> e[maxn * 2];int tag[maxn * 2];void a ...

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

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

  7. [学习笔记]圆方树广义圆方树

    引入 偶尔,我们会遇到一些要在无向图/仙人掌上做的问题,这些问题如果在树上就会比较方便,那么我们就开始考虑能不能把原图等效成一棵树,然后就可以方便地乱搞了? 圆方树就是一种将无向图/仙人掌变成树的数据 ...

  8. 【loj#2524】【bzoj5303】 [Haoi2018]反色游戏(圆方树)

    题目传送门:loj bzoj 题意中的游戏方案可以转化为一个异或方程组的解,将边作为变量,点作为方程,因此若方程有解,方程的解的方案数就是2的自由元个数次方.我们观察一下方程,就可以发现自由元数量=边 ...

  9. 【刷题】BZOJ 2125 最短路

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

最新文章

  1. 用原始方法解析复杂字符串,json一定要用JsonMapper么?
  2. redis-sentinel 主从复制高可用
  3. GridView导出到Excel或Word文件
  4. iOS 添加导航栏两侧按钮
  5. 【经验分享】工程开发与Coding规范
  6. java echarts 散点图,echarts在地图上绘制散点图(任意点)
  7. MySQL建立的索引看_MYSQL索引问题:索引在查询中如何使用?看了很多资料都只说索引的建立。是否建立了就不用再理会?...
  8. 基于sigmoid的文本多标签分类模型代码实现
  9. 玉龙雪山还会存在多久
  10. Luogu P2833 等式 我是傻子x2
  11. C语言打印九九乘法表
  12. 论文相关-MATHTYPE字体对应
  13. SpringBoot中Redis报错:NOAUTH Authentication required.; nested exception is redis.clients.jedis.exceptio
  14. 【论文笔记】气道树分割:A 3D UNet-Graph Neural Network for Airway Segmentation
  15. bzoj4399 魔法少女LJJ
  16. 员工主动提出加班,公司要支付加班费吗?
  17. c语言tab什么意思_收藏 | C语言最全入门笔记
  18. 开源视频监控系统 iSpy
  19. uniapp开发微信小程序-7.用户填写表单信息
  20. jython mysql_讲解jython访问MySQL数据库的具体步骤

热门文章

  1. python自动化办公入门书籍-用Python自动办公,做职场高手 | 「讲文兄博客」
  2. 为什么都建议学java而不是python-学java好还是Python好?
  3. 专科python应届生工资多少-应届生学Python年薪30万,秘诀是什么?
  4. python电脑配置-入门学python需要什么配置的电脑?
  5. 【百度贾磊】汉语语音识别技术重大突破:LSTM+CTC详解(22PPT)
  6. python递归函数入门教程_Python递归函数
  7. sqlplus必须要安装oracle吗,不安装oracle客户端使用sqlplus
  8. 2018服务器 芯片组,2018最新主板知识详解,详谈DIY(主板篇)
  9. jq中get()和eq()的区别
  10. 一图看懂编程语言迁移模式:终点站是Python、Go、JS