传送门
有 n n n 个节点,标号为 1 … n 1\dots n 1…n, m m m 条双向公路连接着这些节点,其中第 i i i 条公路连接着 u i u_i ui 和 v i v_i vi,从一端走到另一端需要 w i w_i wi 秒。现在,马老师打算从家到芜湖机场。
家是节点 1 1 1,机场是节点 n n n,保证存在至少一条从节点 1 1 1 到节点 n n n 的路径。
在第 0 0 0 秒,马老师身处节点 1 1 1,他的目标是尽早到达节点 n n n。根据天气预报,接下来会有 k k k 次暴雨,第 i i i 次暴雨的时间为 l i l_i li 秒至第 r i r_i ri 秒,保证每次暴雨的时间段互不重叠(包括起止时间)。由于马老师忘了带伞,因此在下雨期间,他只能躲在某个节点里面避雨。如果某一个时刻在下暴雨,而马老师还在某条公路上,那么他会被淋惨。
为了帮助马老师尽快回家,上帝决定实现马老师一个愿望。马老师可以指定某一条道路,然后这条道路两端的节点将合并成一个节点(合并出的节点拥有原来两个节点的所有出边)。
请你帮马老师计算,在不被淋惨的前提下最早第多少秒他能回到自己家中?
注:对于一场第 l … r l\dots r l…r 秒的暴雨,若马老师第 r r r 秒从节点出发,或第 l l l 到达某个节点,那么他是不会淋到雨的。
第一行三个数 n , m , k n,m,k n,m,k。
接下来 m m m 行,第 i i i 行三个整数表示 u i , v i , w i u_i,v_i,w_i ui,vi,wi。
接下来 k k k 行,第 i i i 行两个整数表示 l i , r i l_i,r_i li,ri。
第一行一个整数,表示马老师最早第多少秒能回到家中。
样例输入
4 4 3
1 3 5
2 1 4
2 3 4
3 4 1000
4 5
9 10
11 10000
样例输出
9
对于 30 % 30\% 30% 的数据: k = 0 k=0 k=0。
对于 60 % 60\% 60% 的数据: n , m , k ≤ 1 0 3 n,m,k\le 10^3 n,m,k≤103。
对于 100 % 100\% 100% 的数据:
2 ≤ n ≤ 1 5 2\le n\le 1^5 2≤n≤15, 1 ≤ m ≤ 2 × 1 0 5 1\le m\le 2\times 10^5 1≤m≤2×105, 0 ≤ k ≤ 1 0 5 0\le k\le 10^5 0≤k≤105, 1 ≤ w i ≤ 1 0 4 1\le w_i\le 10^4 1≤wi≤104。
0 ≤ l i < r i ≤ 1 0 9 0\le l_i < r_i\le 10^9 0≤li<ri≤109,且保证输入的暴雨时间段互不相交, l i l_i li 严格递增。
直接跑最短路,但是要记录是否使用过愿望,且每次的边权都要二分+st表。
#include<bits/stdc++.h>
#define N 200005
using namespace std;
const int inf=1e9;
int read(){
int op=1,sum=0;char ch=getchar();
while(ch<'0'||ch>'9') {
if(ch=='-') op=-1;ch=getchar();}
while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+ch-'0',ch=getchar();
return op*sum;
}
int n,m,k;
int tot,head[N],ver[N<<1],nex[N<<1],edge[N<<1];
inline void add(int x,int y,int z){
nex[++tot]=head[x];head[x]=tot;ver[tot]=y;edge[tot]=z;
}
int L[N],R[N],Len[N];
int d[N][2],v[N][2],st[N][21],T=20,e[21];
inline int get(int x,int y){
int k=(int)(log((double)(y-x+1))/log(2.0));
return max(st[x][k],st[y-e[k]+1][k]);
}
priority_queue<pair<int, int> > q;
void spfa(){
memset(d,0x3f,sizeof(d));
d[1][0]=0;
q.push(make_pair(0,2));
while(!q.empty()){
int x=(q.top().second>>1),s=(q.top().second&1);q.pop();
if(v[x][s])continue;
v[x][s]=1;
//cout<<x<<" "<<s<<" "<<d[x][s]<<endl;
for(int i=head[x];i;i=nex[i]){
int y=ver[i],w=edge[i],to=d[x][s]+w;
//node now;now.l=d[x][s],now.r=to,now.len=w;
int pos=upper_bound(L+1,L+1+k,d[x][s])-L-1;
if(R[pos]<to){
int l=pos+1,r=k;
while(l<r){
// cout<<l<<" "<<r<<endl;
int mid=(l+r)>>1;
if(get(pos+1,mid)>=w)r=mid;
else l=mid+1;
}
to=L[l]+w;
}
if(d[y][s]>to){
d[y][s]=to;
q.push(make_pair(-d[y][s],(y<<1)|s));
}
if(!s){
if(d[y][s|1]>d[x][s]){
d[y][s|1]=d[x][s];
q.push(make_pair(-d[y][s|1],(y<<1)|s|1));
}
}
}
}
}
int main(){
// freopen("airport.in","r",stdin);
// freopen("airport.out","w",stdout);
n=read(),m=read(),k=read();
for(int i=1;i<=m;++i){
int x=read(),y=read(),z=read();
add(x,y,z);add(y,x,z);
}
int las=0;
for(int i=1;i<=k;++i){
int l=read(),r=read();
L[i]=las,R[i]=l;las=r;
Len[i]=R[i]-L[i];
}
L[++k]=las,R[k]=inf;Len[k]=R[k]-L[k]+1;
for(int i=1;i<=k;++i)st[i][0]=Len[i];
e[0]=1;
for(int i=1;i<=20;++i)e[i]=e[i-1]<<1;
for(int i=1;i<=T;++i){
for(int j=1;j<=k-e[i]+1;++j){
st[j][i]=max(st[j][i-1],st[j+e[i-1]][i-1]);
}
}
// sort(qu+1,qu+1+k);
spfa();
printf("%d\n",min(d[n][0],d[n][1]));
return 0;
}