目录

P3387-【模板】缩点

P3387-【模板】缩点

题目:

题目描述:

给定一个 $n$ 个点 $m$ 条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。

允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。

输入格式:

第一行两个正整数 $n,m$

第二行 $n$ 个整数,依次代表点权

第三至 $m+2$ 行,每行两个整数 $u,v$,表示一条 $u\rightarrow v$ 的有向边。

输出格式:

共一行,最大的点权之和。

样例:

样例输入1:

1
2
3
4
2 2
1 1
1 2
2 1

样例输出1:

1
2

思路:

实现:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include "ybwhead/ios.h"
int n, m;
const int maxn = 1e4 + 10;
const int maxm = 1e5 + 10;
struct egde
{
    int v, nxt;
} e[maxm << 1];
int a[maxn];
int head[maxn], tot;
void add(int u, int v)
{
    e[++tot].v = v;
    e[tot].nxt = head[u];
    head[u] = tot;
}
int dfn[maxn];
int low[maxn];
int num;
int vis[maxn];
stack<int> s;
int su, co[maxn];
int ans[maxn];
void tarjan(int u)
{
    // cout << u << endl;
    dfn[u] = low[u] = ++num;
    s.push(u);
    vis[u] = 1;
    for (int i = head[u]; i; i = e[i].nxt)
    {
        int v = e[i].v;
        if (!dfn[v])
        {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else
        {
            if (vis[v])
            {
                low[u] = min(low[u], dfn[v]);
            }
        }
    }
    if (dfn[u] == low[u])
    {
        ++su;
        // cout << u << endl;
        while (s.top() != u)
        {
            vis[s.top()] = 0;
            co[s.top()] = su;
            ans[su] += a[s.top()];
            s.pop();
        }
        vis[u] = 0;
        co[u] = su;
        ans[su] += a[u];
        s.pop();
    }
}
vector<int> vv[maxn];
int in[maxn];
queue<int> q;
int dis[maxn];
int main()
{
    yin >> n >> m;
    for (int i = 1; i <= n; i++)
        yin >> a[i];
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        yin >> u >> v;
        add(u, v);
    }
    for (int i = 1; i <= n; i++)
        if (!dfn[i])
            tarjan(i);
    // puts("!!!");
    for (int u = 1; u <= n; u++)
    {
        for (int i = head[u]; i; i = e[i].nxt)
        {
            int v = e[i].v;
            // cout << u << "!!!" << v << endl;
            // cout << co[u] << " " << co[v] << endl;
            if (co[u] != co[v])
            {
                vv[co[u]].push_back(co[v]);
                in[co[v]]++;
            }
        }
    }
    for (int i = 1; i <= su; i++)
        if (in[i] == 0)
            q.push(i), dis[i] = ans[i];
    // cout << q.size() << endl;
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int i = 0; i < vv[u].size(); i++)
        {
            int v = vv[u][i];
            --in[v];
            dis[v] = max(dis[v], dis[u] + ans[v]);
            if (in[v] == 0)
            {
                q.push(v);
            }
        }
    }
    // cout << su << endl;
    int ans = 0;
    for (int i = 1; i <= su; i++)
        ans = max(ans, dis[i]);
    yout << ans << endl;
    return 0;
}