hdu 5361 2015多校联赛第六场 In Touch

  题意: 

  每个点可以到左右两个范围内的点并花费为Ci, 问1 到 所有点的最短距离。 


  用普通的优先队列最短路不行,复杂度高,且边较多。


这里要用dijstra的一个性质,那就是在未使用过的点中挑选出离S最近的 X,之后这个X不会再更新,如果用优先队列来写的话就表现为从队列里出来的点不会再被更新

我们设到达V点最近的距离为dis[v],        如果我们把 dis[v] + C[V](和小的优先) 放入优先队列,那么取出来的点去更新它能到达的区间,这些区间内的点必然是最小的,也就是说,这个点能到的区间内的点之后都不不要再更新,为了避免在更新这个点,我们可以将已经更新的点用并查集,这样在下次需要更新这段区间时,我们就可跳过这段区间,直接更新到区间的又端点。 

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2*1e5+10;
typedef long long LL;
LL  L[maxn];
LL R[maxn];
LL dis[maxn];
int f[maxn];
#pragma comment(linker, "/STACK:1024000000,1024000000")
LL c[maxn];
int n;
struct node
{
    int id  ;
    LL dis;
    node(int a ,LL b):id(a),dis(b) {};
    friend bool operator < (node a,node b)
    {
        return a.dis>b.dis;
    }
};
int find(int x)
{
    if (x != f[x])
        f[x] =  find(f[x]);
    return f[x];
}
void Merge(int x,int y)
{
    int bossx = find(x);
    int bossy = find(y);
    if(bossx!=bossy)
    {
        f[bossx] = bossy;
    }
}
void dijkstra(int s)
{
    dis[1] = 0;
    priority_queue<node>q;
    q.push(node(s,c[s]));
    while(!q.empty())
    {
        node now = q.top();
        q.pop();
        //  int u = now.id;
        for(int i = -1; i<2; i+=2)
        {
            int zuo = now.id+ i*L[now.id];
            int you = now.id+ i*R[now.id];
            if(zuo>you)
                swap(zuo,you);
            zuo = max(1,zuo);
            you = min(you,n);
            for(int j = zuo; j<=you; j++)
            {
                j = find(j);
                if(j>you)
                    break;
                if(dis[j]>now.dis)
                {
                    dis[j] = now.dis;
                    q.push(node(j,dis[j]+c[j]));
                }
                if(j+1<you)
                    Merge(j,j+1);
            }
        }
    }
}
const long long INF = 1e17;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i = 1; i<=n; i++)
        {
            scanf("%lld",&L[i]);
            f[i] = i;
            dis[i]  = INF;
        }
        for(int i = 1; i<=n; i++)
        {
            scanf("%lld",&R[i]);
        }
        for(int i = 1; i<=n; i++)
        {
            scanf("%lld",&c[i]);
        }
        dijkstra(1);

        for(int i = 1; i<n; i++)
        {
            if(dis[i]==INF)
            {
                dis[i]=-1;
            }
            printf("%lld ",dis[i]);
        }
        if(dis[n]==INF)
            dis[n] = -1; 
        cout<<dis[n]<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值