本题目直接套用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; }