「JOISC 2020 Day4」治疗计划
description
solution
设dpi:1−Ridp_i:1-R_idpi:1−Ri 都能被救治成功的最小花费
两个治疗方案[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|Ri−Lj+1≥∣Ti−Tj∣
最后要合并成[1,n][1,n][1,n]
相当于如果从Li=1L_i=1Li=1的所有方案出发,如果能与jjj方案合并,则连边i→cjji\rightarrow^{c_j} ji→cjj
求到Rj=nR_j=nRj=n的最短路
-
Ti≥TjT_i\ge T_jTi≥Tj
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_jRi−Lj+1≥Ti−Tj⇔Ri−Ti+1≥Lj−Tj
-
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_jRi−Lj+1≥Tj−Tj⇔Ri+Ti+1≥Lj+Tj
以TjT_jTj为下标建线段树,维护两棵线段树
最短路用dijkstra
跑,线段树可以查找出所有iii的出边点
因为每个点的花费是一定的,所以一定是当前最短路拓展到该点且仅一次
所以每个点只会被用一次(用了就可以删掉了)
O(nlogn)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;
}