Luogu1073 [NOIP2009]最优贸易

题目蓝链

Solution

因为可以随便走,所以显然就是一个缩点+DP,只需要记录每一个强联通分量的最大和最小价格就可以了

Code

#include <bits/stdc++.h>

using namespace std;

#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef pair<int, int> pii;

inline int read() {
    int sum = 0, fg = 1; char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
    for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
    return fg * sum;
}

const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;

vector<int> g[maxn], gg[maxn];

int n, m;
int Min[maxn], Max[maxn], a[maxn], f[maxn];
int d[maxn], low[maxn], dfn, S[maxn], top, pre[maxn], cnt, r[maxn], ans[maxn];
bool v[maxn];

void tarjan(int now) {
    d[now] = low[now] = ++dfn;
    S[++top] = now; v[now] = 1;
    for (int son : g[now]) {
        if (!d[son]) {
            tarjan(son);
            low[now] = min(low[now], low[son]);
        }else if (v[son]) low[now] = min(low[now], d[son]);
    }
    if (d[now] == low[now]) {
        cnt++;
        Max[cnt] = 0, Min[cnt] = inf;
        while (top) {
            int x = S[top--];
            pre[x] = cnt; v[x] = 0;
            Min[cnt] = min(Min[cnt], a[x]);
            Max[cnt] = max(Max[cnt], a[x]);
            if (x == now) break;
        }
    }
}

int main() {
#ifdef xunzhen
    freopen("trade.in", "r", stdin);
    freopen("trade.out", "w", stdout);
#endif

    n = read(), m = read();
    for (int i = 1; i <= n; i++) a[i] = read();
    for (int i = 1; i <= m; i++) {
        int x = read(), y = read(), z = read();
        g[x].push_back(y);
        if (z == 2) g[y].push_back(x);
    }

    for (int i = 1; i <= n; i++) if (!d[i]) tarjan(i);

    for (int i = 1; i <= n; i++)
        for (int j : g[i])
            if (pre[i] != pre[j]) gg[pre[i]].push_back(pre[j]), r[pre[j]]++;

    memset(f, 0x3f, sizeof f);
    queue<int> q;
    for (int i = 1; i <= cnt; i++)
        if (!r[i]) q.push(i);
    f[pre[1]] = Min[pre[1]];

    ans[pre[1]] = Max[pre[1]] - Min[pre[1]];
    while (!q.empty()) {
        int now = q.front();
        q.pop();
        for (int son : gg[now]) {
            if (f[now] < inf) {
                f[son] = min(min(f[son], f[now]), Min[son]);
                ans[son] = max(max(ans[son], ans[now]), Max[son] - f[son]);
            }
            r[son]--; if (!r[son]) q.push(son);
        }
    }

    printf("%d\n", ans[pre[n]]);

    return 0;
}

Summary

这道题网上有很多错误的题解,什么\(dijkstra\)还有\(spfa\)都是错的

除了洛谷有一个神奇的奇短无比的dfs好像是对的

转载于:https://www.cnblogs.com/xunzhen/p/9788257.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值