欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

「JOISC 2020 Day4」治疗计划(线段树+dijkstra最短路)

发布时间:2023/12/3 编程问答 36 豆豆
生活随笔 收集整理的这篇文章主要介绍了 「JOISC 2020 Day4」治疗计划(线段树+dijkstra最短路) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

「JOISC 2020 Day4」治疗计划

description

solution

dpi:1−Ridp_i:1-R_idpi:1Ri 都能被救治成功的最小花费

两个治疗方案[Li,Ri],[Lj,Rj][L_i,R_i],[L_j,R_j][Li,Ri],[Lj,Rj]能够合并成完整的健康区间的条件为Ri−Lj+1≥∣Ti−Tj∣R_i-Lj+1\ge |T_i-T_j|RiLj+1TiTj

最后要合并成[1,n][1,n][1,n]

相当于如果从Li=1L_i=1Li=1的所有方案出发,如果能与jjj方案合并,则连边i→cjji\rightarrow^{c_j} jicjj

求到Rj=nR_j=nRj=n的最短路

  • Ti≥TjT_i\ge T_jTiTj

    Ri−Lj+1≥Ti−Tj⇔Ri−Ti+1≥Lj−TjR_i-L_j+1\ge T_i-T_j\Leftrightarrow R_i-T_i+1\ge L_j-T_jRiLj+1TiTjRiTi+1LjTj

  • Ti<TjT_i<T_jTi<Tj

    Ri−Lj+1≥Tj−Tj⇔Ri+Ti+1≥Lj+TjR_i-L_j+1\ge T_j-T_j\Leftrightarrow R_i+T_i+1\ge L_j+T_jRiLj+1TjTjRi+Ti+1Lj+Tj

TjT_jTj为下标建线段树,维护两棵线段树

最短路用dijkstra跑,线段树可以查找出所有iii的出边点

因为每个点的花费是一定的,所以一定是当前最短路拓展到该点且仅一次

所以每个点只会被用一次(用了就可以删掉了)

O(nlog⁡n)O(n\log n)O(nlogn)

code

#include <queue> #include <cstdio> #include <iostream> #include <algorithm> using namespace std; #define inf 0x7f7f7f7f #define int long long #define maxn 100005 struct node {int t, l, r, c; }cure[maxn]; vector < int > nxt; priority_queue < pair < int, int > > q; int n, m; int dis[maxn];bool cmp( node x, node y ) {return x.t < y.t; }class SegMentTree {private :int t[maxn << 2];public :void build( int num, int l, int r, int k ) {if( l == r ) {t[num] = cure[l].l + k * cure[l].t;return;}int mid = ( l + r ) >> 1;build( num << 1, l, mid, k );build( num << 1 | 1, mid + 1, r, k );t[num] = min( t[num << 1], t[num << 1 | 1] );}void modify( int num, int l, int r, int pos ) {if( l == r ) {t[num] = inf;return;}int mid = ( l + r ) >> 1;if( pos <= mid ) modify( num << 1, l, mid, pos );else modify( num << 1 | 1, mid + 1, r, pos );t[num] = min( t[num << 1], t[num << 1 | 1] );}void query( int num, int l, int r, int L, int R, int k ) {if( L > R || R < l || r < L || t[num] > k ) return;if( l == r ) {nxt.push_back( l );return;}int mid = ( l + r ) >> 1;query( num << 1, l, mid, L, R, k );query( num << 1 | 1, mid + 1, r, L, R, k );} }S, T; signed main() {scanf( "%lld %lld", &n, &m );for( int i = 1;i <= m;i ++ )scanf( "%lld %lld %lld %lld", &cure[i].t, &cure[i].l, &cure[i].r, &cure[i].c );sort( cure + 1, cure + m + 1, cmp );S.build( 1, 1, m, -1 );T.build( 1, 1, m, 1 );for( int i = 1;i <= m;i ++ )if( cure[i].l == 1 ) {dis[i] = cure[i].c;q.push( make_pair( -dis[i], i ) );S.modify( 1, 1, m, i );T.modify( 1, 1, m, i );}while( ! q.empty() ) {int u = q.top().second; q.pop();if( cure[u].r == n ) return ! printf( "%lld\n", dis[u] );nxt.clear();S.query( 1, 1, m, 1, u - 1, cure[u].r - cure[u].t + 1 );T.query( 1, 1, m, u + 1, m, cure[u].r + cure[u].t + 1 );for( int i = 0;i < nxt.size();i ++ ) {int v = nxt[i];dis[v] = dis[u] + cure[v].c;q.push( make_pair( -dis[v], v ) );S.modify( 1, 1, m, v );T.modify( 1, 1, m, v );}}printf( "-1\n" );return 0; }

总结

以上是生活随笔为你收集整理的「JOISC 2020 Day4」治疗计划(线段树+dijkstra最短路)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。