题目
点这里看题目。
分析
首先注意到问题就是一个最短路的模型,但是边是连在区间上的,这提示我们应该使用数据结构优化建图。
考虑一个不那么粗暴的做法。一种想法是,由于用 Dijkstra 跑最短路的时候,只要出了堆就可以不用管了,那么我们可以每次只访问区间内有效的位置;这个位置可以使用链表/并查集维护。
然而这个方法并没有用......Dijkstra 和 BFS 不同的地方在于,Dijkstra 中每个点虽然只会被出一次堆,但是会被访问多次,而 BFS 则只会被访问一次。此题还有一个性质,边权只和边的起点相关,如果我们在堆里维护好到达某个点的最短距离,等到这个最短距离被取出了之后,我们再去找可以到达的点,并且将这个最短距离赋给那些点,就可以保证每个点只访问一次。
小结:
- 理清每个算法之间的差异,避免一些理解错误的问题;
- 注意,求最短路的时候,“计算距离”和“将距离对应到点”并非绑定在一起的,通过将这两个过程拆开我们可以处理这种特殊情况;
代码
#include <queue>
#include <cstdio>
#include <utility>
#include <iostream>
#define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
#define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )
typedef long long LL;
const LL INF = 1e18;
const int MAXN = 2e5 + 5;
template<typename _T>
void read( _T &x )
{
x = 0; char s = getchar(); int f = 1;
while( ! ( '0' <= s && s <= '9' ) ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
x *= f;
}
template<typename _T>
void write( _T x )
{
if( x < 0 ) putchar( '-' ), x = -x;
if( 9 < x ) write( x / 10 );
putchar( x % 10 + '0' );
}
typedef std :: pair<LL, int> Node;
std :: priority_queue<Node, std :: vector<Node>, std :: greater<Node> > q;
LL dist[MAXN];
bool vis[MAXN];
int fa[MAXN];
int l[MAXN], r[MAXN], c[MAXN];
int N;
void MakeSet( const int n ) { rep( i, 1, n ) fa[i] = i; }
int FindSet( const int u ) { return fa[u] = ( fa[u] == u ? u : FindSet( fa[u] ) ); }
void UnionSet( const int u, const int v ) { fa[FindSet( u )] = FindSet( v ); }
void Dijkstra( const int s )
{
MakeSet( N + 1 );
while( ! q.empty() ) q.pop();
rep( i, 1, N ) dist[i] = INF, vis[i] = false;
q.push( std :: make_pair( dist[s] = c[s], s ) );
while( ! q.empty() )
{
int u = q.top().second; q.pop(), vis[u] = true;
int lef = std :: max( u - r[u], 1 ), rig = u - l[u];
if( lef <= rig )
for( int v = FindSet( lef ) ; v <= rig ; v = FindSet( v + 1 ) )
{
if( dist[v] > dist[u] + c[v] )
q.push( std :: make_pair( dist[v] = dist[u] + c[v], v ) );
UnionSet( v, v + 1 );
}
lef = u + l[u], rig = std :: min( N, u + r[u] );
if( lef <= rig )
for( int v = FindSet( lef ) ; v <= rig ; v = FindSet( v + 1 ) )
{
if( dist[v] > dist[u] + c[v] )
q.push( std :: make_pair( dist[v] = dist[u] + c[v] , v ) );
UnionSet( v, v + 1 );
}
}
}
int main()
{
int T;
read( T );
while( T -- )
{
read( N );
rep( i, 1, N ) read( l[i] );
rep( i, 1, N ) read( r[i] );
rep( i, 1, N ) read( c[i] );
Dijkstra( 1 );
rep( i, 1, N )
{
if( vis[i] ) write( dist[i] - c[i] );
else write( -1 ); putchar( i == N ? '
' : ' ' );
}
}
return 0;
}