Wannafly挑战赛2 D.Delete(拓扑排序 + dij预处理 + 线段树维护最小值)

题目链接  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
", dt[s]);
			continue;
		}

		query(1, 1, n, a[x], ans);
		if (ans == INF) puts("-1");
		else printf("%lld
", ans);
	}

	return 0;
}

  

原文地址:https://www.cnblogs.com/cxhscst2/p/7936244.html