题意:给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价。起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权。

解法:参考https://www.cnblogs.com/zj75211/p/7168254.html这位大佬的。学到了建图新姿势。

首先还是先讲讲朴素建图:很容易想到拆点然后把边看成点,对于任意两条边a->b,b->c我们可以连一条权值为min(v1,v2)的a->c的边。容易看出这样的建图极限是n^2的,菊花图上会被卡成傻逼。我们要考虑优化建图:首先还是拆边然后把边看成点,然后我们枚举每一个中间点x(1<x<n),把x的出边按权值从小到大排序,然后小出边小大出边连权值差值的边,大出边向小出边连权值为0的边,x的每条入边向其对应的出边连权值为原边权的边,然后我们创造起点和终点:对于起点向其出边连权值原来的边,对于终点其入边向终点连权值原来的边。最后跑一次Dijkstra即可。

这样的建图看起来有些诡异,我们不妨思考一下为什么这样是对的?其实很简单:因为这样建图能起到和朴素建图一样的作用,这种方法是巧妙的利用了差值起到了一种逐步累加变成正确边长的方法。入边向相应出边的连边保证了经过x点入边的代价,然后通过补差值保证了通过x点出边的代价。并且这样累加的方式可以变成任何一条原来的边,没有任何遗漏。

只能说这样的建图确实十分巧妙,凭蒟蒻自己是想不到的,只能可遇不可求吧qwq。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,int> pii;
const int N=4e5+;
int n,m,s,t;
struct edge{ int x,y,z; }e[N<<];
vector<int> G[N]; int cnt=,head[N],nxt[N<<],to[N<<],len[N<<];
void add_edge(int x,int y,int z) {
nxt[++cnt]=head[x]; to[cnt]=y; len[cnt]=z; head[x]=cnt;
} bool cmp(int t1,int t2) { return e[t1].z<e[t2].z; } void Build() {
for (int i=;i<=*m+;i++) { //起点和终点连边
if (e[i].x==) add_edge(s,i,e[i].z);
if (e[i].y==n) add_edge(i,t,e[i].z);
}
for (int i=;i<n;i++) {
sort(G[i].begin(),G[i].end(),cmp);
for (int j=;j<G[i].size();j++) {
add_edge(G[i][j]^,G[i][j],e[G[i][j]].z); //i点入边向出边连边
if (j!=) add_edge(G[i][j],G[i][j-],); //大出边向小出边连0
if (j<G[i].size()-) //小出边向大出边连差值
add_edge(G[i][j],G[i][j+],e[G[i][j+]].z-e[G[i][j]].z);
}
}
} priority_queue<pii> q;
LL dis[N<<]; bool vis[N<<];
LL Dijkstra() {
memset(dis,0x3f,sizeof(dis));
dis[s]=;
q.push(make_pair(,s));
while (!q.empty()) {
pii u=q.top(); q.pop();
if (vis[u.second]) continue;
vis[u.second]=;
for (int i=head[u.second];i;i=nxt[i]) {
int y=to[i];
if (dis[u.second]+len[i]<dis[y]) {
dis[y]=dis[u.second]+len[i];
q.push(make_pair(-dis[y],y));
}
}
}
return dis[t];
} int main()
{
cin>>n>>m;
s=; t=m*+;
for (int i=;i<=m;i++) {
int x,y,z; scanf("%d%d%d",&x,&y,&z);
e[i*]=(edge){x,y,z};
e[i*+]=(edge){y,x,z};
G[x].push_back(i*); G[y].push_back(i*+); //G[i]保存i出边编号
}
Build();
cout<<Dijkstra()<<endl;
return ;
}

BZOJ 4289 最短路+优化建图的更多相关文章

  1. BZOJ 4276 [ONTAK2015]Bajtman i Okrągły Robin 费用流+线段树优化建图

    Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢 ...

  2. BZOJ 3073: [Pa2011]Journeys Dijkstra+线段树优化建图

    复习一下线段树优化建图:1.两颗线段树的叶子节点的编号是公用的. 2.每次连边是要建两个虚拟节点 $p1,p2$ 并在 $p1,p2$ 之间连边. #include <bits/stdc++.h ...

  3. bzoj3073: [Pa2011]Journeys 线段树优化建图

    bzoj3073: [Pa2011]Journeys 链接 BZOJ 思路 区间和区间连边.如何线段树优化建图. 和单点连区间类似的,我们新建一个点,区间->新点->区间. 又转化成了单点 ...

  4. 【BZOJ4383】[POI2015]Pustynia 线段树优化建图

    [BZOJ4383][POI2015]Pustynia Description 给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r ...

  5. AtCoder Regular Contest 069 F Flags 二分,2-sat,线段树优化建图

    AtCoder Regular Contest 069 F Flags 二分,2-sat,线段树优化建图 链接 AtCoder 大意 在数轴上放上n个点,点i可能的位置有\(x_i\)或者\(y_i\ ...

  6. loj#2255. 「SNOI2017」炸弹 线段树优化建图,拓扑,缩点

    loj#2255. 「SNOI2017」炸弹 线段树优化建图,拓扑,缩点 链接 loj 思路 用交错关系建出图来,发现可以直接缩点,拓扑统计. 完了吗,不,瓶颈在于边数太多了,线段树优化建图. 细节 ...

  7. bzoj4383 [POI2015]Pustynia 拓扑排序+差分约束+线段树优化建图

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4383 题解 暴力的做法显然是把所有的条件拆分以后暴力建一条有向边表示小于关系. 因为不存在零环 ...

  8. BZOJ-3495 前缀优化建图2-SAT

    题意:有n个城镇被分成了k个郡,有m条连接城镇的无向边.要求给每个郡选择一个城镇作为首都,满足每条边至少有一个端点是首都. 解法:以前没学过,参考https://blog.csdn.net/linkf ...

  9. codeforces 787D - Legacy 线段树优化建图,最短路

    题意: 有n个点,q个询问, 每次询问有一种操作. 操作1:u→[l,r](即u到l,l+1,l+2,...,r距离均为w)的距离为w: 操作2:[l,r]→u的距离为w 操作3:u到v的距离为w 最 ...

随机推荐

  1. linux 系统磁盘管理体系

    目录 linux 系统磁盘管理体系 一.磁盘的基本概念 二.磁盘的内部结构 三.磁盘的外部结构 四.磁盘的接口及类型 五.fdisk磁盘分区实践 六.gdisk 分区 七.parted 高级分区工具. ...

  2. Pandas之loc\iloc\ix

    ---------------------------------------------------------------------------------------------------- ...

  3. xshell xftp使用

    1.xftp传输的中文上去乱码,是因为传输时使用GB2312,而服务端不是GB2312 使用UTF-8编码上传即可

  4. 利用Stream模式进行文件拷贝

    const fs = require('fs'); const file = fs.createReadStream("readfile.js"); const outputFil ...

  5. 运用pool进程池启动大量子进程

    # Pool进程池类 from multiprocessing import Pool import os import time import random def run(index): prin ...

  6. oracle trim无效?

    这里说说如果是全角空格怎么去除 方法一 trim(TO_SINGLE_BYTE('aaa')) 方法二 SELECT TRIM(replace('aaa',' ','')) FROM dual

  7. python3.x filter,map,reduce浅析

    #map用法: #传递函数api进入map去执行,把字符串第一个字母变大写, #其他变小写返回 def format_name(s): s=s.lower() print(s) return s[0] ...

  8. Mybatis基于接口注解配置SQL映射器(一)

    上文已经讲解了基于XML配置的SQL映射器,在XML配置的基础上MyBatis提供了简单的Java注解,使得我们可以不配置XML格式的Mapper文件,也能方便的编写简单的数据库操作代码. Mybat ...

  9. 77 geometry process

    0 引言 记录几何方面的一些处理技术. 1 任意多边形面积计算:包含凸多边形和凹多边形 转载了JustDoIT https://www.cnblogs.com/TenosDoIt/p/4047211. ...

  10. node 桌面应用开发

    1.node桌面应用开发的框架 :electron 和 nw.js     https://www.jianshu.com/p/c6bdb087e60d 2.使用electron构建跨平台Node.j ...