洛谷P10199 [湖北省选模拟 2024] 时与风 / wind 题解
题目链接:P10199 [湖北省选模拟 2024] 时与风 / wind
题意:
风带来故事的种子,时间使之神话。
你在 \(N\) 个锚点间,沿着 \(M\) 条有向航道,使用风之翼进行飞行。锚点依次编号为 \(1,2,\cdots,N\),有向航道依次编号为 \(1,2,\cdots,M\)。第 \(i\) 条航道的出发锚点为 \(u_i\),到达锚点为 \(v_i\)。
由于巴巴斯托与时间存在神秘的联系,第 \(i\) 条航道将在时刻 \(O_i\) 开启,在时刻 \(C_i\) 后关闭。也就是说,对于任意的 \(O_i \le t \le C_i\),你可以在时刻 \(t\) 由锚点 \(u_i\) 进入航道 \(i\)。进入航道后,空间上,你将直接到达锚点 \(v_i\),时间上,时间将等概率的变化为 \([L_i,R_i]\) 中的一个实数对应的时刻。注意到达一个锚点后,你必须在同一时刻立刻进入下一段航道,否则你必须在此结束飞行。
你将从锚点 \(S\) 出发,尝试访问锚点 \(i(1\le i\le N)\),你需要对于锚点 \(i\) 确定一条路径 \(E_1,E_2,E_3,\cdots,E_k\),其中 \(E_x(1\le x\le k)\) 表示一条航道。要求 \(E_1\) 从锚点 \(S\) 出发,\(E_k\) 到达锚点 \(i\),且对于 \(1\le j<k\),满足 \(E_j\) 的到达锚点与 \(E_{j+1}\) 的出发锚点相同。一条路径是稳定路径,当且仅当无论每次通过航道后时间如何变化,都可以走完整条路径。一条稳定路径的到达时间是通过路径前往锚点 \(i\) 时,最晚的可能到达锚点 \(i\) 的时刻。访问锚点 \(i\) 的稳定到达时间 \(T_i(i \neq S)\) 是所有到达 \(i\) 的稳定路径中到达时间的最小值。你可以在任意非负时刻出发。如果不存在访问锚点 \(i\) 的稳定路径或 \(i=S\),则 \(T_i=0\)。
请你求出 \(T_i(1\le i\le N)\) 的最大值。
输入格式:
输入共 \(M+1\) 行。
输入的第一行为三个整数 \(N,M,S\),分别表示锚点数、航道数和起点锚点。
接下来 \(M\) 行,每行包含六个整数 \(u_i,v_i,O_i,C_i,L_i,R_i\),描述了第 \(i\) 条航道的有关信息,变量具体含义见题目描述部分。
输出格式:
输出一行一个整数,表示 \(T_i\) 的最大值。
数据范围:
\(1 \le N,M \le 5\times 10^5\),\(1 \le O_i,L_i \le 20\),\(1 \le O_i \le C_i \le 10^9\),\(1 \le L_i \le R_i \le 10^9\),\(1\le S \le N\)。
一般题目中出现“实数内随机”都是吓人的,显然这道题也是这样的。
实际上我们只关心一条路径最早和最晚到的时刻,这决定了下一条边是否能发挥它的作用。
然而这道题并不适用最短路算法,因为我们对于两条路径含有不重合时间段的情况无法讨论其优先级。
显然这是一个二维偏序问题,我们需要固定其中的一维,同时算法也换成普通的 bfs。
可以发现,因为 \(1\le O_i,L_i\le 20\) 所以我们可以用优先队列维护起始时刻 \(1\) 到 \(20\) 的每条边
对于每条路径,我们在小于等于其 \(O_i\) 的每一个位置取出大于等于其 \(R_i\) 的所有边
因为每个点的答案仅与更新它的边有关,即只有边能够更新答案,所以每条边至多产生 \(1\) 的复杂度贡献
时间复杂度 \(\mathcal{O}(V_Lm + m \log m)\)
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
namespace FastIO
{
#define gc() readchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e6 + 15)
char buf1[SIZ], *p1, *p2;
char readchar()
{
if(p1 == p2){ p1 = buf1,p2 = buf1 + fread(buf1, 1, SIZ, stdin); }
return p1 == p2? EOF : *p1++;
}
template<typename T>void read(T &k)
{
char ch = gc(); T x = 0, f = 1;
while(!isdigit(ch)){ if(ch == '-'){ f = -1; }ch = gc(); }
while(isdigit(ch)){ x = (x << 1) + (x << 3) + (ch ^ 48); ch = gc(); }
k = x * f;
}
template<typename A, typename ...B>
void read(A &x, B &...y) { return read(x), read(y...); }
template<typename T>void write(T k)
{
if(k < 0){ k = -k; pc('-'); }
static T stk[66]; T top = 0;
do{ stk[top++] = k % 10, k /= 10; } while(k);
while(top) { pc(stk[--top] + '0'); }
}
}using namespace FastIO;
#define N ((int)(5e5 + 15))
int n,m,res,T[N];
struct node{ int v, a, b, c, d, id; };
bool operator<(node a, node b) { return a.b < b.b; }
vector<node> vec[N];
priority_queue<node> p[N][21];
queue<int> q; set<node> st[N];
void upd(int u, int x) { T[u] = (T[u] ? min(T[u], x) : x); }
void insert(int u, node x)
{
for(int i = x.c; i; i--)
{
while(!p[u][i].empty() && p[u][i].top().b >= x.d)
{
auto tmp = p[u][i].top(); p[u][i].pop();
q.push(tmp.v); st[u].insert(tmp); upd(tmp.v, tmp.d);
}
}
}
void solve(int s)
{
for(int i = 1; i <= n; i++)
for(auto x : vec[i]) p[i][x.a].push(x);
for(auto x : vec[s]) {
upd(x.v, x.d); q.push(x.v); insert(x.v, x);
}
while(!q.empty())
{
int u = q.front(); q.pop();
if(!T[u]) continue;
for(auto x : st[u]) insert(x.v, x);
st[u].clear();
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
int s; read(n, m, s);
for(int i = 1; i <= m; i++)
{
int u, v, a, b, c, d;
read(u, v, a, b, c, d);
vec[u].push_back({v, a, b, c, d, i});
}
solve(s);
for(int i = 1; i <= n; i++) up(res, T[i]);
write(res); pc('\n');
return 0;
}
参考文献: