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

HINT
对于100%的数据,N<=10000,Q<=10000


这题写的我真TM舒服……

首先对仙人掌建出一棵圆方树,考虑树上的边权,如果是圆点连圆点,则边权不变;如果是圆点连方点,则边权为圆点到方点所属环上,dfs序最小的点的距离

然后我们考虑lca的两种情况,如果lca是圆点,那么我们直接输出圆方树上的两点之间距离;如果lca是方点,我们找到\(x,y\)在lca儿子中的祖先节点\(x',y'\),则答案为\(dis_{x\rightarrow x'}+dis_{x'\rightarrow y'}+dis_{y'\rightarrow y}\)

(树剖求lca找\(x',y'\)时细节贼难受……)

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Fi first
#define Se second
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef pair<int,int>pii;
typedef unsigned long long ull;
inline char gc(){static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){int x=0,f=1; char ch=gc();for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';return x*f;
}
inline int read(){int x=0,f=1; char ch=getchar();for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<3)+(x<<1)+ch-'0';return x*f;
}
inline void print(int x){if (x<0)    putchar('-'),x=-x;if (x>9)    print(x/10);putchar(x%10+'0');
}
const int N=1e4;
int V[N+10],cnt,n,m,q;
struct node{int lca,x,y;node(){lca=x=y=0;}node(int _l,int _x,int _y){lca=_l,x=_x,y=_y;}void insert(int _l,int _x,int _y){lca=_l,x=_x,y=_x;}
};
struct S1{  int pre[(N<<2)+10],now[(N<<1)+10],child[(N<<2)+10],val[(N<<2)+10],tot;int fa[(N<<1)+10],deep[(N<<1)+10],top[(N<<1)+10],Rem[(N<<1)+10],size[(N<<1)+10],dis[(N<<1)+10];void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}void dfs(int x){deep[x]=deep[fa[x]]+1,size[x]=1;for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){if (son==fa[x]) continue;fa[son]=x,dis[son]=dis[x]+val[p];dfs(son),size[x]+=size[son];if (size[Rem[x]]<size[son]) Rem[x]=son;}}void build(int x){if (!x) return;top[x]=Rem[fa[x]]==x?top[fa[x]]:x;build(Rem[x]);for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){if (son==fa[x]||son==Rem[x])    continue;build(son);}}node LCA(int x,int y){int lastx=0,lasty=0;while (top[x]!=top[y]){if (deep[top[x]]<deep[top[y]])  lasty=top[y],y=fa[top[y]];else    lastx=top[x],x=fa[top[x]];}if (x==y)   return node(x,lastx,lasty);if (deep[x]<deep[y])    return node(x,lastx,Rem[x]);else    return node(y,Rem[y],lasty);//WA了好几次,画了图才发现应该这样写……}
}RST;//Round Square Tree
struct S2{int pre[(N<<2)+10],now[N+10],child[(N<<2)+10],val[(N<<2)+10];int fa[N+10],dfn[N+10],low[N+10],fv[N+10],dis[N+10],stack[N+10],belong[N+10];bool instack[N+10];int tot,Time,top,num;void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}int distant(int x,int y,int pos){if (dfn[x]<dfn[y])  swap(x,y);return min(dis[x]-dis[y],V[pos]-(dis[x]-dis[y]));}void dfs(int x){dfn[x]=++Time;for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){if (son==fa[x]) continue;if (!dfn[son]){fa[son]=x,dis[son]=dis[x]+val[p];fv[son]=val[p],dfs(son);}else   if (dfn[son]<dfn[x]){V[++cnt]=val[p],RST.insert(cnt+n,son,0);for (int i=x;i!=son;i=fa[i])    V[cnt]+=fv[i];for (int i=x;i!=son;i=fa[i])    RST.insert(cnt+n,i,distant(i,son,cnt));}}}void tarjan(int x,int fa){//不论如何枚举顺序都是一样的,那么dfn就算再次dfs也是一样的dfn[x]=low[x]=++Time;instack[stack[++top]=x]=1;for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){if (son==fa)    continue;if (!dfn[son])  tarjan(son,x),low[x]=min(low[x],low[son]);else    if (instack[son])   low[x]=min(low[x],dfn[son]);}if (dfn[x]==low[x]){belong[x]=++num;instack[x]=0;while (stack[top]!=x)   belong[stack[top]]=num,instack[stack[top--]]=0;top--;}}void init(){Time=0;memset(dfn,0,sizeof(dfn));}
}OT;//Original Tree
struct S3{int x,y,z;void insert(int _x,int _y,int _z){x=_x,y=_y,z=_z;}
}Line[(N<<1)+10];
int main(){n=read(),m=read(),q=read();for (int i=1;i<=m;i++){int x=read(),y=read(),z=read();OT.insert(x,y,z);Line[i].insert(x,y,z);}OT.dfs(1),OT.init(),OT.tarjan(1,0);for (int i=1;i<=m;i++)if (OT.belong[Line[i].x]!=OT.belong[Line[i].y])RST.insert(Line[i].x,Line[i].y,Line[i].z);RST.dfs(1),RST.build(1);for (int i=1;i<=q;i++){int x=read(),y=read();node tmp=RST.LCA(x,y);if (tmp.lca<=n) printf("%d\n",RST.dis[x]+RST.dis[y]-2*RST.dis[tmp.lca]);else{int res=RST.dis[x]+RST.dis[y]-RST.dis[tmp.x]-RST.dis[tmp.y];res+=OT.distant(tmp.x,tmp.y,tmp.lca-n);printf("%d\n",res);}}return 0;
}

转载于:https://www.cnblogs.com/Wolfycz/p/10279492.html

[BZOJ2125]最短路相关推荐

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

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

  2. BZOJ2125 最短路

    每个点有两个值,一个是从根到这个点的最短路d[i],一个是从根沿dfs树到这个点的距离rd[i]. 之后是一个很牛逼的建图,把环上的点都连到环中深度最浅的点得到一颗树,并维护每个点所在的环以及每个环的 ...

  3. bzoj3047: Freda的传呼机bzoj2125: 最短路

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3047 http://www.lydsy.com/JudgeOnline/problem.ph ...

  4. bzoj3047:Freda的传呼机bzoj2125: 最短路

    完结撒花!!!!!!!!!!! 最后一题填坑1A仙人掌WWWWWWW我真流弊 首先把环拆开,环中每一个点连向环的根,然后搞LCA,答案就是套路的d[x]+d[y]-d[lca]*2 然后就可以发现,其 ...

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

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

  6. 图论5:Tarjan!塔尖!

    文章目录 小模板 强联通分量 割点 桥 边双连通分量 点双连通分量 支配树 CodeChef - GRAPHCNT 3281: 小P的烦恼 test2018.3.3:problem C 仙人掌和圆方树 ...

  7. 仙人掌最短路--bzoj2125

    与基环树最短路的思想相同 我们只需要对每个子树求lca,在环上我们以d数组记录一个同向的前缀路径长度 可以方便的算出环上两点之间的最短距离,也就是环两侧距离取min,具体看注释 当我们求x与y之间的距 ...

  8. [C] [最短路] 只有5行的算法:Floyd-Warshall

    终于学到求最短路了,终于来到我最喜欢的算法--Floyd-Warshall了!今天还有点小激动呢! 我喜欢它,当然是因为它逻辑十分简单咯!真的只有5行诶! Floyd-Warshall算法 题目描述 ...

  9. BZOJ4152 AMPPZ2014 The Captain(最短路)

    事实上每次走到横坐标或纵坐标最接近的点一定可以取得最优方案.于是这样连边跑最短路就可以了. #include<iostream> #include<cstdio> #inclu ...

最新文章

  1. syslog源码_Gunicorn源码分析01--目录结构
  2. java jsp学习指南_JSP教程–最终指南
  3. HTML如何添加锚点,我先收藏为敬
  4. 列表推导(list comprehension)--Python
  5. 数据挖掘:实用案例分析 下载_【实用干货】17 种服装印花工艺(图文案例分析)...
  6. 零元学Expression Blend 4 - Chapter 7 什麽?影片不再是印象中的方框框!!!看Blend 4如何把影片镶入字里...
  7. python h5s文件 压缩_如何用python解压zip压缩文件
  8. Java 8 新特性 Stream类的collect方法
  9. 一套代码两端运行不靠谱?是时候放弃 C++ 跨 Android、iOS 端开发!
  10. 第二章--物理层--重点
  11. HashMap源码剖析(代码基于JDK11)
  12. 2017 Multi-University Training Contest 5 solutions BY 吉如一
  13. 推荐系统常用推荐系统算法(协同过滤算法等)-人工智能AI
  14. 文书档案管理(文书与档案管理共用)【1】
  15. A股数据日级前复权数据补全
  16. 威廉玛丽学院计算机专业,威廉玛丽学院CS排名2020年掌握的流程盘点
  17. linux开机启动grub rescue,开机出现 grub rescue的解决方法探索
  18. 2017年各大电商平台双11回顾:值得借鉴和改进的运营手段
  19. 问题描述:宏代码导致无法打开文件
  20. m1/m1Pro/m1Max芯片下载win11-arm镜像

热门文章

  1. visio生成数据表图
  2. jenkins pipeline api获取stage的详细信息_Jenkins + Docker 助力 Serverless 应用构建与部署...
  3. ffmpeg-win32-v3.2.4 下载_MVBOX下载|MVBOX 7.1.0.4官方版
  4. vs2019 缺android sdk,VS2019由于缺少NuGet Microsoft.NET.Sdk.Functions程序包而无法加载项目,但也无法添加此程序包(示例代码)...
  5. Windows使用筛选器来处理异常
  6. c#endread怎么打印出来_打印机打印出来是白板是怎么回事
  7. leetcode 77. 组合 思考分析
  8. java uuid静态方法_Java UUID compareTo()方法与示例
  9. css中的node.js_在Node App中使用基本HTML,CSS和JavaScript
  10. spring boot 集合mysql_Spring boot整合mysql和druid