[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;
}