[BZOJ1576]安全路径travel-最短路径树+并查集
来源:互联网 发布:装修公司源码 编辑:程序博客网 时间:2024/06/15 15:27
说在前面
= =本来这个题被放在数据机构刷题提单里,然后还备注着说是”最短路径树+树链剖分+线段树维护”,然而实际上好像并不需要,只需要一个”最短路径树+并查集维护”就可以了。
题目
先给链接:BZOJ1576传送门(这是一道权限题XD)
题意
简单的说,就是求出1号点到每个点路径(该路径不能经过最短路的最后一条边)的最短距离是多少。
题解
首先,这道题相当于是让我们求出不走某一条边的最短路
我们先搞出最短路径树,这一步用dijkstra堆优化
搞出来之后,我们假设根节点是1号点,那么对于不在最短路径树上的某一条边u->v(本来是无向边,把无向边看成两条有向边即可),对于1号点到u路径上的任意一点x,那么x的一条其他路径就是1->v->u->x
设dist[i]表示1号点(根节点)到i号点的距离,这条”其他路径”的长度就可以表示成
注意到,对于每个这样的节点x,dist[x]一定是固定的,并且对于每一条边,都拥有自己的dist[u]+dist[v]+len(u->v),那我们只需要用每条边依次去更新每个点的ans就好了。
Emmmmmm……
注意到这个复杂度是十分高的,我们需要对这个算法进行优化
我们可以发现,一个点,假设它是x,可能会被更新很多次,但是实际上最优的那个更新,一定是由min( dist[u]+dist[v]+len(u->v) )-dist[x]得到的。我们只需要对所有的边按照dist[u]+dist[v]+len(u->v)从小到大排个序,那么当一个点被更新的时候,一定就是那个最优值,即之后的对该点的更新都不如之前的优,每个点只更新一次就好了。这一步我们可以用并查集进行维护。
然后就可以愉快的AC啦qwq
下面是自带大常数的代码
fa数组是最短路径树的fa
而b数组相当于是并查集的fa
vis是为了在堆优化的时候防止重复更新
其他的数组应该不难懂= =
/************************************************************** Problem: 1576 User: Izumihanako Language: C++ Result: Accepted Time:1320 ms Memory:9944 kb****************************************************************/#include <queue>#include <cstdio>#include <cstring>#include <algorithm>#define pr pair<int,int>#define fi first#define se secondusing namespace std ;int N , M , tp , head[100005] , b[100005] , ans[100005] ;int dist[100005] , vis[100005] , fa[100005] , dep[100005] ;struct Path{ int fr , to , len , pre ; bool operator < ( const Path &A ) const { return dist[fr] + dist[to] + len < dist[A.fr] + dist[A.to] + A.len ; }}p[400005] ;void In ( int t1 , int t2 , int t3 ){ p[++tp].pre = head[t1] ; p[ head[t1] = tp ].to = t2 ; p[tp].len = t3 ; p[tp].fr = t1 ;}priority_queue< pr , vector<pr> , greater<pr> > q ;void Dijk(){ memset( dist , 0x3f , sizeof( dist ) ) ; pr S = make_pair( 0 , 1 ) ; q.push( S ) ; fa[1] = 1 ; dep[1] = dist[1] = 0 ; while( !q.empty() ){ pr u = q.top() ; q.pop() ; if( vis[u.se] ) continue ; vis[u.se] = 1 ; for( int i = head[u.se] ; i ; i = p[i].pre ){ int v = p[i].to ; if( dist[v] > dist[u.se] + p[i].len ){ dist[v] = dist[u.se] + p[i].len ; fa[v] = u.se ; dep[v] = dep[u.se] + 1 ; q.push( make_pair( dist[v] , v ) ) ; } } }}int find( int x ){ if( b[x] == x ) return x ; return b[x] = find( b[x] ) ;}void solve(){ for( int i = 1 ; i <= N ; i ++ ) b[i] = i ; memset( ans , -1 , sizeof( ans ) ) ; for( int i = 1 ; i <= tp ; i ++ ){ if( p[i].fr == fa[p[i].to] || p[i].to == fa[p[i].fr] ) continue ; int u = find( p[i].fr ), v = find( p[i].to ), val = p[i].len + dist[p[i].fr] + dist[p[i].to] ; while( v != u ){ if( dep[v] > dep[u] ) swap( u , v ) ; ans[u] = val - dist[u] ; int F_u = find( u ) , FF_u = find( fa[u] ) ; b[F_u] = b[FF_u] ; u = b[FF_u] ; } }}int main(){ scanf( "%d%d" , &N , &M ) ; for( int i = 1 , t1 , t2 , t3 ; i <= M ; i ++ ){ scanf( "%d%d%d" , &t1 , &t2 , &t3 ) ; In( t1 , t2 , t3 ) ; In( t2 , t1 , t3 ) ; } Dijk() ; sort( p + 1 , p + tp + 1 ) ; solve() ; for( int i = 2 ; i <= N ; i ++ ) printf( "%d\n" , ans[i] ) ;}
阅读全文
0 0
- [BZOJ1576]安全路径travel-最短路径树+并查集
- 【最短路径树+可并堆/树链剖分】BZOJ1576 [Usaco2009 Jan]安全路经Travel
- [BZOJ1576][Usaco2009 Jan]安全路径Travel(堆优化dijkstra+并查集)
- bzoj1576[Usaco2009 Jan]安全路径Travel(堆优化dijkstra+并查集)
- 【bzoj1576】【安全路径Travel】【dijkstra+树链剖分】
- 最小生成树 并查集 最短路径
- HDU2433 Travel 最短路径树
- 【USACO】安全路径(计数/求和以及最值小探讨)(最有生成树之最短路径树,LCA,最值问题,并查集)
- 1576: [Usaco2009 Jan]安全路经Travel 最短路径树+树链剖分+线段树
- 51nod 1366 贫富差距 (并查集+最短路径)
- hdu 2433 Travel(最短路径树+删边+bfs)
- hdu 2433 Travel (最短路径树)
- 【HDU 2433】Travel (BFS+最短路径树)
- 【BZOJ1576】[Usaco2009 Jan]安全路经Travel【最短路树】【树链剖分】【线段树】
- [Usaco2009 Jan]安全路经Travel(最短路树+并查集/树链剖分)
- poj2457 - Part Acquisition (最短路径问题)(邻接表 Dijkstra + 并查集 )
- 用并查集(find-union)实现迷宫算法以及最短路径求解
- poj 3984迷宫问题(bfs求最短路径 类似并查集保存上个节点 保存最短路径)
- MATLAB中cell数组的全面介绍
- U盘安装镜像WIN10 64 专业版 BMR转GPT 的问题
- Maven的安装
- Google支付服务端client_id和client_secret及refresh_token参数申请
- Hadoop完全分布式搭建过程
- [BZOJ1576]安全路径travel-最短路径树+并查集
- 解决Eclipse新版本出现An error has occurred,See error log for more details的错误
- HOG+ADABOOST方式训练头肩检测模型
- 个人收集学习资料
- BGP状态转换
- 使用QII中的PowerPlay Power Analyzer估算FPGA功耗
- apache flume架构与运行原理
- python assert的介绍
- 大话数据结构(一)