Live2D

Date Pickup 题解

link

Solution

首先我们可以求出任意的 \(\text{dis}(u,i),\text{dis}(i,t)\)

考虑二分答案,对于当前二分的 \(x\),我们最终接到电话可行的点一定就是就是那些 \(\text{dis}(i,t)\le x\)\(i\) 点。对于边 \((u,v,w)\),如果存在 \(w+\text{dis}(v,t)\le x\),那么在经过这条边时接到电话也是来的及的。所以我们就可以找到一个子图,可以在这上面游荡,随时都可以走到。但是我们要走到这个子图肯定就需要里面有点满足我 \(a\) 时刻接到电话就可以走,即 \(\text{dis}(s,i)+\text{dis}(i,t)\le a+x\)

不过如果我们这个子图不能耗时耗到 \(b\) 的话,肯定也是不满足的,所以我们可以对其做 topo 排序后进行 dp,看是否能耗到 \(b\) 即可,注意的是我们一开始可以等会,不过不能超过 \(a+x-\text{dis}(i,t)\),否则你 \(a\) 时刻接到电话就到不了了。

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define int long long
#define MAXN 100005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

int a,b,n,m,d1[MAXN],d2[MAXN],dp[MAXN],deg[MAXN];

#define pii pair<int,int>
#define se second
#define fi first

bool vis[MAXN];
vector <pii> e[MAXN],g1[MAXN],g2[MAXN];
void dijkstra (int s,vector <pii> *g,int *d){
	priority_queue <pii,vector <pii>,greater <pii> > q;
	memset (vis,0,sizeof (bool) * (n + 2)),memset (d,0x3f,sizeof (int) * (n + 2)),d[s] = 0,q.push ({d[s],s});
	while (!q.empty()){
		pii it = q.top();q.pop ();
		if (it.fi != d[it.se] || vis[it.se]) continue;
		vis[it.se] = 1;int u = it.se;
		for (pii it : g[u]){
			int v = it.fi,w = it.se;
			if (d[v] > d[u] + w){
				d[v] = d[u] + w;
				if (!vis[v]) q.push ({d[v],v});
			}
		}
	}
}

bool can[MAXN],arr[MAXN];

void bfs (int mid){
	memset (deg,0,sizeof (deg)),memset (arr,0,sizeof (arr));
	queue <int> q;
	for (Int i = 1;i <= n;++ i){
		e[i].clear ();
		if (can[i] && d1[i] + d2[i] <= a + mid) q.push (i),arr[i] = 1;
	}
	while (!q.empty()){
		int u = q.front();q.pop ();
		for (pii it : g1[u]){
			int v = it.fi,w = it.se;
			if (w + d2[v] <= mid){
				if (!arr[v]) arr[v] = 1,q.push (v);
				e[u].push_back (it),deg[v] ++;
			}
		}
	}
//	for (Int i = 1;i <= n;++ i) cout << i << ": " << arr[i] << endl;
}

bool topo (int mid){
	memset (dp,0xcf,sizeof (dp));queue <int> q;
	for (Int i = 1;i <= n;++ i) if (arr[i] && !deg[i]) q.push (i);
	while (!q.empty()){
		int u = q.front();q.pop ();
		if (d1[u] <= a + mid - d2[u]) chkmax (dp[u],a + mid - d2[u]);
		if (dp[u] >= b) return 1;
		for (pii it : e[u]){
			int v = it.fi,w = it.se;
			chkmax (dp[v],dp[u] + w);
			if (!-- deg[v]) q.push (v);
		}
	}
	for (Int i = 1;i <= n;++ i) if (arr[i] && deg[i]) return 1;
	return 0;
}

bool check (int mid){
	for (Int i = 1;i <= n;++ i) can[i] = (d2[i] <= mid);
	if (can[1]) return 1;
	bfs (mid);
	return topo (mid);
}

signed main(){
	read (a,b,n,m);
	for (Int i = 1,u,v,w;i <= m;++ i) read (u,v,w),g1[u].push_back ({v,w}),g2[v].push_back ({u,w});
	dijkstra (1,g1,d1),dijkstra (n,g2,d2);
	int l = 0,r = 1e13,ans = 0;
	while (l <= r){
		int mid = l + r >> 1;
		if (check (mid)) ans = mid,r = mid - 1;
		else l = mid + 1;
	}
	write (ans),putchar ('\n');
	return 0;
}
posted @ 2022-01-24 10:27  Dark_Romance  阅读(88)  评论(0编辑  收藏  举报