1 条题解
-
0
思路
考虑图论建模,连接 边,表示 。
那么一个点 的 在某一个时刻能被确定,则表示在当前图上所有点要么能走到 ,要么能被 走到。进一步的,所有 小于 的点都能走到 ,所有 大于 的点都能被 走到。
继续刻画这个性质,将所有边连起来,对这个 DAG 跑拓扑排序得到一个拓扑序,记作 。注意到拓扑序有一个很好的性质,若 ,则一定有 ;反之有 。于是 check 在当前图上是否能被确定,可以转化为 check 小于 的 能否走到 , 大于 的 能否被 走到。
由于任意时刻图都是一个 DAG 森林,所以对于前者 是 的点构成子图中唯一一个出度为 的点;反之是唯一一个入度为 的点。这两个问题是对称的,下面只讨论一种情况的解法。
对 扫描线,指针扫到 的时候将满足 的所有 边加入,维护每一个点第一次有出度的时刻,可以用线段树/优先队列等数据结构维护。复杂度 。
Code
#include <bits/stdc++.h> #define re register #define fst first #define snd second #define chmin(a,b) (a = min(a,b)) using namespace std; typedef pair<int,int> pii; const int N = 8e5 + 10; const int inf = 1e9 + 10; int n,m; pii E[N]; vector<int> g[N]; vector<pii> to1[N],to2[N]; int ans1[N],ans2[N]; int tim,deg[N],dfn[N],pid[N]; inline int read(){ int r = 0,w = 1; char c = getchar(); while (c < '0' || c > '9'){ if (c == '-') w = -1; c = getchar(); } while (c >= '0' && c <= '9'){ r = (r << 3) + (r << 1) + (c ^ 48); c = getchar(); } return r * w; } inline void topsort(){ queue<int> q; for (re int i = 1;i <= n;i++){ if (!deg[i]) q.push(i); } assert(q.size()); while (!q.empty()){ int u = q.front(); q.pop(); pid[dfn[u] = ++tim] = u; for (int v:g[u]){ if (!(--deg[v])) q.push(v); } } } struct{ #define ls(u) (u << 1) #define rs(u) (u << 1 | 1) #define mid (tr[u].l + tr[u].r >> 1) struct node{ int l,r,Max; }tr[N << 2]; inline void pushup(int u){ tr[u].Max = max(tr[ls(u)].Max,tr[rs(u)].Max); } inline void build(int u,int l,int r){ tr[u] = {l,r,inf}; if (l == r) return; build(ls(u),l,mid); build(rs(u),mid + 1,r); } inline void update(int u,int x,int k){ if (tr[u].l == tr[u].r) return (chmin(tr[u].Max,k)),void(); if (x <= mid) update(ls(u),x,k); else update(rs(u),x,k); pushup(u); } inline int query(int u,int l,int r){ if (l > r) return 0; if (l <= tr[u].l && tr[u].r <= r) return tr[u].Max; if (l <= mid && r > mid) return max(query(ls(u),l,r),query(rs(u),l,r)); else if (l <= mid) return query(ls(u),l,r); else return query(rs(u),l,r); } #undef ls #undef rs #undef mid }T; int main(){ n = read(),m = read(); fill(ans1,ans1 + n + 3,inf); fill(ans2,ans2 + n + 3,inf); for (re int i = 1,a,b;i <= m;i++){ a = read(),b = read(); g[a].push_back(b); E[i] = {a,b}; deg[b]++; } topsort(); T.build(1,1,n); for (re int i = 1;i <= m;i++){ to1[dfn[E[i].fst]].push_back({dfn[E[i].snd],i}); to2[dfn[E[i].snd]].push_back({dfn[E[i].fst],i}); } T.build(1,1,n); for (re int u = 1;u <= n;u++){ for (pii v:to2[u]) T.update(1,v.fst,v.snd); ans1[pid[u]] = T.query(1,1,u - 1); } T.build(1,1,n); for (re int u = n;u;u--){ for (pii v:to1[u]) T.update(1,v.fst,v.snd); ans2[pid[u]] = T.query(1,u + 1,n); } for (re int i = 1;i <= n;i++){ int val = max(ans1[i],ans2[i]); printf("%d ",(val >= inf) ? -1 : val); } return 0; }
- 1
信息
- ID
- 11010
- 时间
- 3000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者