HDU 5361(dijkstra变形)

本题目直接套用dijkstra算法会超时的,因为每个点被更新的次数可能很多、

那么dijkstra算法的核心是,去没有加入到(已经求得最短路的集合)外,d值最小的加入集合,并松弛连边,

(证明 : 集合外权值最小的点,一定存在一条最短路,那么取这条最短上在集合外的第一个点v,那么这个点已经达到最优值,d[v] = best[ v] <= best[ u ]<=d[u] ,又v,u同在集合外面,d[ u] <=d[ v ],要是两个不等式成立,那么u已经达到最优值。)

对于本题目,有个特殊性,即从一点出发,到左右两个集合所有点的权值相同,那么只需要没把一个求得best的点加入集合时,加入node(best[ u ] + cost [u ] , id),按第一维排序,

那么取出的第一个node,node.id 到达的所有点都将达到最优路径值,其值为该node的第一维值。那么这样把所有到达的点同操作加入,即每个点只进入集合一次。nlog(n)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <cctype>
#include <set>
#define ls rt<<1
#define rs rt<<1|1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define clr(a,x) memset(a,x,sizeof(a))
#define rep1(i,x,y) for(int i=x;i<=y;i++)
#define rep(i,n) for(int i=0;i<(int)n;i++)
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll oo = 0x3f3f3f3f3f3f3f;
const int N = 2*1e5+1000;
set<int> vis;
struct node{
   ll dis;
   int id;
   node(){}
   node(ll dis,int id):dis(dis),id(id){}
   bool operator<(const node& rhs)const{
      if(dis!=rhs.dis) return dis<rhs.dis;
      return id<rhs.id;
   }
};
set<node> Q;
int l[N],r[N],n;
ll c[N],d[N];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
       scanf("%d",&n);
       rep(i,n) scanf("%d",&l[i]);
       rep(i,n) scanf("%d",&r[i]);
       rep(i,n) scanf("%I64d",&c[i]);
       vis.clear();
       rep1(i,1,n-1) vis.insert(i);
       memset(d,-1,sizeof(d));
       d[0]=0; Q.clear();
       Q.insert(node(c[0],0));
       while(!Q.empty()){
            node u = *Q.begin();
            Q.erase(Q.begin());
            rep(i,2){
               int L,R;
               if(!i) L=u.id-r[u.id],R=u.id-l[u.id];
               else L=u.id+l[u.id],R=u.id+r[u.id];
               set<int>::iterator it = vis.lower_bound(L),it2;
               while(it !=vis.end() && (*it)<=R){
                    int v = *it;
                    d[v] = u.dis;
                    Q.insert(node(u.dis+c[v],v));
                    vis.erase(it++);
               }
            }
       }
       rep(i,n){
           if(i) printf(" ");
           printf("%I64d",d[i]);
       }  printf("\n");
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值