[BZOJ1179] [Apio2009]Atm(tarjan缩点 + spfa)

传送门

题意

N个点M条边的有向图

每个点有点权

从某一个结点出发

问能获得的最大点权和

一个点的点权最多被计算一次

N<=500000 M<=500000

思路

先tarjan缩点,然后就形成一个dag,无环,所以直接spfa求最长路就行。

也可以先缩点,然后拓扑排序 + dp 搞。

代码

  1 #include <map>
  2 #include <queue>
  3 #include <stack>
  4 #include <cstdio>
  5 #include <cstring>
  6 #include <iostream>
  7 
  8 const int MAXN = 500001;
  9 int n, m, s, p, cnt, cnt1, tim, sz, ans;
 10 int head[MAXN], to[MAXN], next[MAXN], head1[MAXN], to1[MAXN], next1[MAXN];
 11 int a[MAXN], dfn[MAXN], low[MAXN], belong[MAXN], val[MAXN], dis[MAXN];
 12 bool ins[MAXN], vis[MAXN];
 13 std::map <int, int> map1[MAXN];
 14 std::stack <int> S;
 15 std::queue <int> q;
 16 
 17 inline int max(int x, int y)
 18 {
 19     return x > y ? x : y;
 20 }
 21 
 22 inline int min(int x, int y)
 23 {
 24     return x < y ? x : y;
 25 }
 26 
 27 inline int read()
 28 {
 29     int f = 1, x = 0;
 30     char ch = getchar();
 31     for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
 32     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
 33     return f * x;
 34 }
 35 
 36 inline void add(int x, int y)
 37 {
 38     to[cnt] = y;
 39     next[cnt] = head[x];
 40     head[x] = cnt++;
 41 }
 42 
 43 inline void add1(int x, int y)
 44 {
 45     to1[cnt1] = y;
 46     next1[cnt1] = head1[x];
 47     head1[x] = cnt1++;
 48 }
 49 
 50 inline void dfs(int u)
 51 {
 52     int i, v;
 53     S.push(u);
 54     ins[u] = 1;
 55     dfn[u] = low[u] = ++tim;
 56     for(i = head[u]; i ^ -1; i = next[i])
 57     {
 58         v = to[i];
 59         if(!dfn[v])
 60         {
 61             dfs(v);
 62             low[u] = min(low[u], low[v]);
 63         }
 64         else if(ins[v]) low[u] = min(low[u], dfn[v]);
 65     }
 66     if(!(low[u] ^ dfn[u]))
 67     {
 68         sz++;
 69         do
 70         {
 71             v = S.top();
 72             S.pop();
 73             belong[v] = sz;
 74             ins[v] = 0;
 75         }
 76         while(u ^ v);
 77     }
 78 }
 79 
 80 inline void spfa()
 81 {
 82     int i, u, v;
 83     dis[belong[s]] = val[belong[s]];
 84     q.push(belong[s]);
 85     vis[belong[s]] = 1;
 86     while(!q.empty())
 87     {
 88         u = q.front();
 89         q.pop();
 90         vis[u] = 0;
 91         for(i = head1[u]; i ^ -1; i = next1[i])
 92         {
 93             v = to1[i];
 94             if(dis[v] < dis[u] + val[v])
 95             {
 96                 dis[v] = dis[u] + val[v];
 97                 if(!vis[v])
 98                 {
 99                     vis[v] = 1;
100                     q.push(v);
101                 }
102             }
103         }
104     }
105 }
106 
107 int main()
108 {
109     int i, x, y, u, v;
110     n = read();
111     m = read();
112     memset(head, -1, sizeof(head));
113     memset(head1, -1, sizeof(head1));
114     for(i = 1; i <= m; i++)
115     {
116         x = read();
117         y = read();
118         add(x, y);
119     }
120     for(i = 1; i <= n; i++) a[i] = read();
121     s = read();
122     p = read();
123     dfs(s);
124     for(i = 1; i <= n; i++) val[belong[i]] += a[i];
125     for(u = 1; u <= n; u++)
126         for(i = head[u]; i ^ -1; i = next[i])
127         {
128             v = to[i];
129             if(belong[u] ^ belong[v] && !map1[belong[u]][belong[v]])
130                 map1[belong[u]][belong[v]] = 1, add1(belong[u], belong[v]);
131         }
132     spfa();
133     for(i = 1; i <= p; i++)
134     {
135         x = read();
136         ans = max(ans, dis[belong[x]]);
137     }
138     printf("%d
", ans);
139     return 0;
140 }
View Code
 
原文地址:https://www.cnblogs.com/zhenghaotian/p/6858372.html