[SDOI2010][最短路] 大陆争霸

题面


我们将每个节点的最短距离记录为如下两个量:\(arr\)\(into\),分别代表达到当前点的最短距离满足当前节点前置条件的最短距离,最短距离在两者中取大值。

然后硬跑最短路就行了。

代码:

# include <iostream>
# include <cstdio>
# include <queue>
# include <cstring>
# define MAXN 300005
# define MAXM 700005
# define pii std::pair<int, int>
# define mkp std::make_pair

struct edge{
	int v, next, w;
}e[MAXM]; int hd[MAXN], cntE;
struct node{
	int to, next;
}nd[MAXN]; int hdnd[MAXN], cntN;
int degIn[MAXN], dis[MAXN]; bool vis[MAXN];
int arr[MAXN], into[MAXN]; // 到达时间,可以进入的时间

void AddE(int u, int v, int w){
	e[++cntE] = (edge){v, hd[u], w};
	hd[u] = cntE;
}
void AddN(int from, int to){
	nd[++cntN] = (node){to, hdnd[from]};
	hdnd[from] = cntN;
}

int main(){
	int n, m;

	scanf("%d%d", &n, &m);

	for(int i = 1, u, v, w; i <= m; i++){
		scanf("%d%d%d", &u, &v, &w);
		AddE(u, v, w);
	}

	for(int i = 1, l, x; i <= n; i++){
		scanf("%d", &l);
		for(int j = 1; j <= l; j++){
			scanf("%d", &x);
			AddN(x, i); degIn[i]++;
		}
	}

	std::priority_queue<pii, std::vector<pii>, std::greater<pii> >H;
	memset(dis, 0x3f, sizeof(dis)); dis[1] = 0;
	memset(arr, 0x3f, sizeof(arr)); arr[1] = 0;
	// memset(into ,0x3f, sizeof(into)); into[1] = 0;
	H.push(mkp(dis[1], 1)); // degIn[1] = 0;

	while(H.size()){
		// printf("FUCK\n");
		int now = H.top().second; H.pop();
		if(!vis[now]){
			vis[now] = true;
			for(int i = hd[now]; i; i = e[i].next){
				if(arr[e[i].v] > dis[now] + e[i].w){
					arr[e[i].v] = dis[now] + e[i].w;
					if(!degIn[e[i].v]){
						dis[e[i].v] = std::max(arr[e[i].v], into[e[i].v]);
						H.push(mkp(dis[e[i].v], e[i].v));
					}
				}
			}
			for(int i = hdnd[now]; i; i = nd[i].next){
				into[nd[i].to] = std::max(into[nd[i].to], dis[now]);
				degIn[nd[i].to]--;
				if(!degIn[nd[i].to]){
					dis[nd[i].to] = std::max(into[nd[i].to], arr[nd[i].to]);
					H.push(mkp(dis[nd[i].to], nd[i].to));
				}
			}
		}
	}

	printf("%d", dis[n]);

	return 0;
}
posted @ 2020-09-30 11:13  ChPu437  阅读(81)  评论(0编辑  收藏  举报