1 条题解

  • 0
    @ 2026-4-25 22:52:20

    更好的阅读体验

    思路

    考虑图论建模,连接 xyx \to y 边,表示 rka<rkbrk_a < rk_b

    那么一个点 uurkrk 在某一个时刻能被确定,则表示在当前图上所有点要么能走到 uu,要么能被 uu 走到。进一步的,所有 rkvrk_v 小于 rkurk_u 的点都能走到 uu,所有 rkvrk_v 大于 rkurk_u 的点都能被 uu 走到。

    继续刻画这个性质,将所有边连起来,对这个 DAG 跑拓扑排序得到一个拓扑序,记作 dfnidfn_i。注意到拓扑序有一个很好的性质,若 rku<rkvrk_u < rk_v,则一定有 dfnu<dfnvdfn_u < dfn_v;反之有 dfnu>dfnvdfn_u > dfn_v。于是 check rkurk_u 在当前图上是否能被确定,可以转化为 check dfnvdfn_v 小于 uuvv 能否走到 uudfnvdfn_v 大于 uuvv 能否被 uu 走到。

    由于任意时刻图都是一个 DAG 森林,所以对于前者 uudfnvdfnudfn_v \leq dfn_u 的点构成子图中唯一一个出度为 00 的点;反之是唯一一个入度为 00 的点。这两个问题是对称的,下面只讨论一种情况的解法。

    dfnidfn_i 扫描线,指针扫到 tt 的时候将满足 dfnx,dfnytdfn_x,dfn_y \leq t 的所有 (x,y)(x,y) 边加入,维护每一个点第一次有出度的时刻,可以用线段树/优先队列等数据结构维护。复杂度 Θ(nlogn)\Theta(n \log n)

    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
    上传者