「HDU5361」In Touch

题目

点这里看题目。

分析

首先注意到问题就是一个最短路的模型,但是边是连在区间上的,这提示我们应该使用数据结构优化建图

考虑一个不那么粗暴的做法。一种想法是,由于用 Dijkstra 跑最短路的时候,只要出了堆就可以不用管了,那么我们可以每次只访问区间内有效的位置;这个位置可以使用链表/并查集维护。

然而这个方法并没有用......Dijkstra 和 BFS 不同的地方在于,Dijkstra 中每个点虽然只会被出一次堆,但是会被访问多次,而 BFS 则只会被访问一次。此题还有一个性质,边权只和边的起点相关,如果我们在堆里维护好到达某个点的最短距离,等到这个最短距离被取出了之后,我们再去找可以到达的点,并且将这个最短距离赋给那些点,就可以保证每个点只访问一次。

小结:

  1. 理清每个算法之间的差异,避免一些理解错误的问题;
  2. 注意,求最短路的时候,“计算距离”和“将距离对应到点”并非绑定在一起的,通过将这两个过程拆开我们可以处理这种特殊情况;

代码

#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 ? '\n' : ' ' );
        }
    }
    return 0;
}
posted @ 2021-08-18 19:01  crashed  阅读(41)  评论(0编辑  收藏  举报