「JOISC 2020 Day4」治疗计划
description
solution
设 d p i : 1 − R i dp_i:1-R_i dpi:1−Ri 都能被救治成功的最小花费
两个治疗方案 [ L i , R i ] , [ L j , R j ] [L_i,R_i],[L_j,R_j] [Li,Ri],[Lj,Rj]能够合并成完整的健康区间的条件为 R i − L j + 1 ≥ ∣ T i − T j ∣ R_i-Lj+1\ge |T_i-T_j| Ri−Lj+1≥∣Ti−Tj∣
最后要合并成 [ 1 , n ] [1,n] [1,n]
相当于如果从 L i = 1 L_i=1 Li=1的所有方案出发,如果能与 j j j方案合并,则连边 i → c j j i\rightarrow^{c_j} j i→cjj
求到 R j = n R_j=n Rj=n的最短路
-
T i ≥ T j T_i\ge T_j Ti≥Tj
R i − L j + 1 ≥ T i − T j ⇔ R i − T i + 1 ≥ L j − T j R_i-L_j+1\ge T_i-T_j\Leftrightarrow R_i-T_i+1\ge L_j-T_j Ri−Lj+1≥Ti−Tj⇔Ri−Ti+1≥Lj−Tj
-
T i < T j T_i<T_j Ti<Tj
R i − L j + 1 ≥ T j − T j ⇔ R i + T i + 1 ≥ L j + T j R_i-L_j+1\ge T_j-T_j\Leftrightarrow R_i+T_i+1\ge L_j+T_j Ri−Lj+1≥Tj−Tj⇔Ri+Ti+1≥Lj+Tj
以 T j T_j Tj为下标建线段树,维护两棵线段树
最短路用dijkstra
跑,线段树可以查找出所有
i
i
i的出边点
因为每个点的花费是一定的,所以一定是当前最短路拓展到该点且仅一次
所以每个点只会被用一次(用了就可以删掉了)
O ( n log 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;
}