「JOISC 2014 Day1」巴士走读

「JOISC 2014 Day1」巴士走读

题解部分:

(如果不怎么喜欢看推导的人可以直接看下面的关键部分,在段尾会有标注(或者看完定义直接看代码))

本题让我们求到达点n需要最晚何时到达点1,我们可以看成为了乘坐到达点n的车,最晚需要何时到达点1。

对于一辆终点为点n的车X,我们必须在它开走之前到它的始发站P,于是我们必须知道需要在X的发车时间之前到达这个点最晚需要何时到达点1。而这和到达这个P的公交车有关系。以此类推。

推导至此,我们知道为了解决这个问题,需要知道为了赶上每辆公交车最晚需要何时到达点1,记这个为某辆公交车的value。同时得支持这个查询操作:为了在某个时间之前到达点x最晚需要何时到达点1。(定义,关键部分)【当然这道题也可以用最短路算法维护上述两个信息】

能更新一辆公交车的value的,只有另一辆公交车的到站时间比它的始发时间小。故我们按照公交车的到站时间从小到大枚举(为什么不能按照始发时间从小到大枚举下面会有解释)

始发站是1的公交车,它的value就是它的发车时刻。对于始发站不是1的公交车X,那么它的value就是在这辆公交车到达时间之前到达X的始发站的公交车的value最大值。这个怎么维护呢?如果我们用树状数组维护这个,空间是完全不够的。(关键部分)

但倘若假设此时我们按照每辆公交车的到站时间从小到大枚举,那么枚举每次到达P的公交车都是当前最迟到达P的公交车,如果它的value没有之前到达P的公交车的value大的话,它是没有价值的,不用加入答案数组即可。(前面的也是推理,后面是关键部分)我们可以用一个pair数组维护这个,一个pair元素的含义就是在时间first之后到达X的公交车的最大value为second。pair数组内的pair按first排序。故假设一次询问要询问在Q之前到达这个点X的value,只用找到第一个first小于Q的pair的socond即可。(关键部分)

当然对于一辆公交车,如果不能用任何一种方法使人在它发车之前到它的始发站,那么它的value就是-1(无限小).

代码还是很短的:

#include<cstdio>
#include<algorithm>
#include<vector>
#define M 300005
using namespace std;
struct node{
	int From,to,tim1,tim2,Ed;
	bool operator <(const node &x)const{
		return tim2<x.tim2;
	}
}A[M];
int n,m,q;
vector<int>S[M],E[M];
void Solve(){
	sort(A+1,A+m+1);
	for(int i=1;i<=n;i++)S[i].push_back(-1),E[i].push_back(0);//本人不怎么习惯用pairQWQ 
	for(int i=1;i<=m;i++){
		int a=A[i].From,b=A[i].to,x=A[i].tim1,y=A[i].tim2,mx;//mx就是这辆公交车的value 
		if(a==1)mx=x;//如果起点就是1 
		else mx=S[a][upper_bound(E[a].begin(),E[a].end(),x)-E[a].begin()-1];//找到在i这辆公交车到达时间之前到达a的公交车的value最大值 
		if(mx>S[b][S[b].size()-1])S[b].push_back(mx),E[b].push_back(y);//如果它的value可以这个pair数组 
	}
	for(int i=1;i<=q;i++){
		int Q;
		scanf("%d",&Q);
		printf("%d\n",S[n][upper_bound(E[n].begin(),E[n].end(),Q)-E[n].begin()-1]);//找到在Q之前到达n的公交车的value最大值 
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)scanf("%d%d%d%d",&A[i].From,&A[i].to,&A[i].tim1,&A[i].tim2);
	scanf("%d",&q);
	Solve();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35320178/article/details/89219495
今日推荐