题目链接 D.Delete
考虑到原图是个DAG,于是我们可以求出每个点的拓扑序。
然后预处理出起点到每个点的最短路$ds[u]$,
和所有边反向之后从终点出发到每个点的最短路$dt[u]$。
令点$u$的拓扑序为$a(u)$。
对于特定的一条边$(u, v, w)$,相当于给所有拓扑序为$[a(u) + 1, a[v] - 1]$的点贡献了一条总长度为$ds[u] + dt[v] + w$的路径。
我们在询问点$u$的时候找到对$u$点贡献的所有路径中长度最小的即可。
特别地,当$s$无法到达$u$或$u$无法到达t时,输出原图从$s$到$t$的最短路即可。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define lson i << 1, L, mid
#define rson i << 1 | 1, mid + 1, R
typedef long long LL;
const int N = 1e5 + 10;
const LL INF = 1e18;
int n, m, s, t, q;
LL ans;
LL ds[N], dt[N];
LL mi[N << 2];
struct node{
int u;
LL w;
friend bool operator < (const node &a, const node &b){
return a.w > b.w;
}
};
vector <node> v[N], g[N];
int a[N], deg[N];
void dij(int s, LL dis[], vector <node> v[]){
priority_queue <node> q;
static bool vis[N];
rep(i, 1, n) dis[i] = 1e18, vis[i] = false;
q.push({s, 0});
dis[s] = 0;
while (!q.empty()){
int u = q.top().u; q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (auto edge : v[u]) if (dis[u] + edge.w < dis[edge.u]){
dis[edge.u] = dis[u] + edge.w;
q.push({edge.u, dis[edge.u]});
}
}
}
void getdag(){
queue <int> q;
int cnt = 0;
rep(i, 1, n){
if (deg[i] == 0) a[i] = ++cnt, q.push(i);
}
while (!q.empty()){
int x = q.front(); q.pop();
for (auto edge : v[x]){
--deg[edge.u];
if (deg[edge.u] == 0) a[edge.u] = ++cnt, q.push(edge.u);
}
}
}
void build(int i, int L, int R){
mi[i] = INF;
if (L == R) return;
int mid = (L + R) >> 1;
build(lson);
build(rson);
}
void update(int i, int L, int R, int l, int r, LL val){
if (l <= L && R <= r){
mi[i] = min(mi[i], val);
return;
}
int mid = (L + R) >> 1;
if (l <= mid) update(lson, l, r, val);
if (r > mid) update(rson, l, r, val);
}
void query(int i, int L, int R, int x, LL &ans){
ans = min(ans, mi[i]);
if (L == R) return;
int mid = (L + R) >> 1;
if (x <= mid) query(lson, x, ans);
else query(rson, x, ans);
}
int main(){
scanf("%d%d%d%d", &n, &m, &s, &t);
rep(i, 1, m){
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
v[x].push_back({y, z});
g[y].push_back({x, z});
++deg[y];
}
getdag();
dij(s, ds, v);
dij(t, dt, g);
build(1, 1, n);
rep(i, 1, n){
for (auto edge : v[i]){
if (a[i] + 1 < a[edge.u] && ds[i] != INF && dt[edge.u] != INF){
update(1, 1, n, a[i] + 1, a[edge.u] - 1, ds[i] + dt[edge.u] + edge.w);
}
}
}
scanf("%d", &q);
while (q--){
int x;
scanf("%d", &x);
ans = INF;
if (ds[x] == INF || dt[x] == INF){
printf("%lld\n", dt[s]);
continue;
}
query(1, 1, n, a[x], ans);
if (ans == INF) puts("-1");
else printf("%lld\n", ans);
}
return 0;
}