DTOJ#5207. 芜湖机场,请求起飞

传送门
n n n 个节点,标号为 1 … n 1\dots n 1n 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 lr 秒的暴雨,若马老师第 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,k103

对于 100 % 100\% 100% 的数据:

2 ≤ n ≤ 1 5 2\le n\le 1^5 2n15 1 ≤ m ≤ 2 × 1 0 5 1\le m\le 2\times 10^5 1m2×105 0 ≤ k ≤ 1 0 5 0\le k\le 10^5 0k105 1 ≤ w i ≤ 1 0 4 1\le w_i\le 10^4 1wi104

0 ≤ l i < r i ≤ 1 0 9 0\le l_i < r_i\le 10^9 0li<ri109,且保证输入的暴雨时间段互不相交, 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值