题意:给出一个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. ionic3中使用docker 完成build代码,更新过程记录。

    1.若未安装cordova 需先安装cordova 包: npm install -g cordova 2.安装docker 可查看官方文档进行一步步的安装:https://docs.docker.c ...

  2. Codeforces 1188D Make Equal DP

    题意:给你个序列,你可以给某个数加上2的幂次,问最少多少次可以让所有的数相等. 思路(官方题解):我们先给序列排序,假设bit(c)为c的二进制数中1的个数,假设所有的数最后都成为了x, 显然x &g ...

  3. [css]等高列的简单实现

    又碰到css等高布局的问题,发现以前没有总结,这里再把基本原理写一下吧. 1.负边距控制法. <div id="content"> <div class=&quo ...

  4. 转 top、postop、scrolltop、offsetTop、scrollHeight、offsetHeight、clientHeight

    1.top 此属性仅仅在对象的定位(position)属性被设置时可用.否则,此属性设置会被忽略. 复制代码 代码如下: <div style=" position:absolute; ...

  5. range类型(Python)

    range 不是 iterator >>> R = range(3) >>> next(R) Traceback (most recent call last): ...

  6. 【leetcode】1005. Maximize Sum Of Array After K Negations

    题目如下: Given an array A of integers, we must modify the array in the following way: we choose an i an ...

  7. C/C++ C++ 11 std::bind()

    { #define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA ...

  8. 【多线程】ConcurrentLinkedQueue 的实现原理

    1. 引言 在并发编程中我们有时候需要使用线程安全的队列.如果我们要实现一个线程安全的队列有两种实现方式:一种是使用阻塞算法,另一种是使用非阻塞算法.使用阻塞算法的队列可以用一个锁(入队和出队用同一把 ...

  9. hdu 4352 XHXJ's LIS (数位dp+状态压缩)

    Description #define xhxj (Xin Hang senior sister(学姐)) If you do not know xhxj, then carefully readin ...

  10. 【Flutter学习】之动画实现原理浅析(二)

    1. 介绍 本文会从代码层面去介绍Flutter动画,因此不会涉及到Flutter动画的具体使用. 1.1 Animation库 Flutter的animation库只依赖两个库,Dart库以及phy ...