嘘~ 正在从服务器偷取页面 . . .

洛谷P6145 [USACO20FEB]Timeline G 题解


洛谷P6145 [USACO20FEB]Timeline G 题解

题目链接:P6145 [USACO20FEB]Timeline G

题意

Bessie 在过去的 \(M\) 天内参加了 \(N\) 次挤奶。但她已经忘了她每次挤奶是在哪个时候了。

对于第 \(i\) 次挤奶,Bessie 记得它不早于第 \(S_i\) 天进行。另外,她还有 \(C\) 条记忆,每条记忆形如一个三元组 \((a,b,x)\),含义是第 \(b\) 次挤奶在第 \(a\) 次挤奶结束至少 \(x\) 天后进行。

现在请你帮 Bessie 算出在满足所有条件的前提下,每次挤奶的最早日期。

保证 Bessie 的记忆没有错误,这意味着一定存在一种合法的方案,使得:

  • \(i\) 次挤奶不早于第 \(S_i\) 天进行,且不晚于第 \(M\) 天进行;
  • 所有的记忆都得到满足;

输入格式

第一行三个整数 \(N,M,C\)。保证 \(1 \leq N,C \leq 10^5\)\(2 \leq M \leq 10^9\)

接下来一行包含 \(N\) 个整数 \(S_1, S_2 , \ldots, S_n\),保证 \(\forall 1 \leq i \leq n\),都满足 \(1 \leq S_i \leq M\)

下面 \(C\) 行每行三个整数 \(a,b,x\),描述一条记忆。保证 \(a \neq b\),且 \(1 \leq x \leq M\)

输出格式

输出 \(N\) 行,每行一个整数,第 \(i\) 行的数表示第 \(i\) 次挤奶的最早日期。

对于 \(b - a \ge c\) ,移项可得 \(a + c \le b\)

然后我们连一条有向边 \(a \to b\) ,跑一遍最长路就能得到了。每个结点的最长路初始值就是给的 \(S_i\)

因为题目保证有解,所以这张图一定是个 DAG ,我们直接跑一遍 \(\mathtt{topo\_sort}\) 就好了

注意这里有一个常见误区。为什么我们不把它变成 \(b + c \ge a\) ,连 \(b \to a\) ,边权为 \(c\) 然后跑最短路呢?

因为题目给出了 \(S\) ,而 \(S_i\) 的含义为 \(a \ge S_a\) 。如果我们以 \(S_b\)\(b\) 的初值去跑,可能无法满足 \(a \ge S_a\)

从逻辑上说,我们并不知道每个结点的真实值,我们只知道他们的下界。

那么我们做的其实就是把这个过程反过来,从 \(a\) 跑到 \(b\) ,也就是正解的连边。

时间复杂度 \(\mathcal{O}(n)\)

代码:

#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; }
#define N ((int)(1e5+15))

int n,m,c,pos=1,head[N],in[N],f[N];
struct Edge { int u,v,w,next; } e[N];
void addEdge(int u,int v,int w)
{ e[++pos] = {u,v,w,head[u]}; head[u] = pos; ++in[v]; }
queue<int> q;
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> m >> c;
    for(int i=1; i<=n; i++) cin >> f[i];
    for(int i=1,u,v,w; i<=c; i++)
    {
        cin >> u >> v >> w;
        addEdge(u,v,w);
    }
    for(int i=1; i<=n; i++) if(!in[i]) q.push(i);
    
    while(!q.empty())
    {
        int u = q.front(); q.pop();
        for(int i=head[u]; i; i=e[i].next)
        {
            int v = e[i].v;
            up(f[v], f[u] + e[i].w);
            if(!(--in[v])) q.push(v);
        }
    }
    for(int i=1; i<=n; i++) cout << f[i] << '\n';
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录