bzoj 1179 [APIO 2009]Atm(APIO水题) - Tarjan - spfa

Input

  第一行包含两个整数N、M。N表示路口的个数,M表示道路条数。接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号。接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数。接下来一行包含两个整数S、P,S表示市中心的编号,也就是出发的路口。P表示酒吧数目。接下来的一行中有P个整数,表示P个有酒吧的路口的编号

Output

输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。

Sample Input

6 7
1 2
2 3
3 5
2 4
4 1
2 6
6 5
10
12
8
16
1 5
1 4
4
3
5
6

Sample Output

47

Hint

  50%的输入保证N, M<=3000。所有的输入保证N, M<=500000。每个ATM机中可取的钱数为一个非负整数且不超过4000。输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。


  觉得这道题和某道noip题(买卖水晶球的题)比较像,这道题似乎不能双向spfa,但是可以先用Tarjan找到强联通分量,然后缩点,这样就是一个有向无环图,就可以进行spfa,在有酒吧的点找最大值。

Code

  1 /**
  2  * bzoj
  3  * Problem#1179
  4  * Accepted
  5  * Time:6280ms
  6  * Memory:56800k
  7  */
  8 #include<iostream>
  9 #include<fstream> 
 10 #include<sstream>
 11 #include<algorithm>
 12 #include<cstdio>
 13 #include<cstring>
 14 #include<cstdlib>
 15 #include<cctype>
 16 #include<cmath>
 17 #include<ctime>
 18 #include<map>
 19 #include<stack>
 20 #include<set>
 21 #include<queue>
 22 #include<vector>
 23 #ifndef WIN32
 24 #define AUTO "%lld"
 25 #else
 26 #define AUTO "%I64d"
 27 #endif
 28 using namespace std;
 29 typedef bool boolean;
 30 #define inf 0xfffffff
 31 #define smin(a, b) (a) = min((a), (b))
 32 #define smax(a, b) (a) = max((a), (b))
 33 template<typename T>
 34 inline boolean readInteger(T& u) {
 35     char x;
 36     int aFlag = 1;
 37     while(!isdigit((x = getchar())) && x != '-' && x != -1);
 38     if(x == -1)    {
 39         ungetc(x, stdin);
 40         return false;
 41     }
 42     if(x == '-') {
 43         aFlag = -1;
 44         x = getchar();
 45     }
 46     for(u = x - '0'; isdigit((x = getchar())); u = u * 10 + x - '0');
 47     u *= aFlag;
 48     ungetc(x, stdin);
 49     return true;
 50 }
 51 
 52 ///map template starts
 53 typedef class Edge{
 54     public:
 55         int end;
 56         int next;
 57         Edge(const int end = 0, const int next = 0):end(end), next(next) {    }
 58 }Edge;
 59 
 60 typedef class MapManager{
 61     public:
 62         int ce;
 63         int *h;
 64         Edge *edge;
 65         MapManager() {    }
 66         MapManager(int points, int limit):ce(0) {
 67             h = new int[(const int)(points + 1)];
 68             edge = new Edge[(const int)(limit + 1)];
 69             memset(h, 0, sizeof(int) * (points + 1));
 70         }
 71         inline void addEdge(int from, int end) {
 72             edge[++ce] = Edge(end, h[from]);
 73             h[from] = ce;
 74         }
 75         Edge& operator [] (int pos) {
 76             return edge[pos];
 77         }
 78 }MapManager;
 79 #define m_begin(g, i) (g).h[(i)]
 80 ///map template ends
 81 
 82 int n, m, s, p;
 83 int* moneys;
 84 MapManager g;
 85 boolean *rest;
 86 
 87 inline void init() {
 88     readInteger(n);
 89     readInteger(m);
 90     moneys = new int[(const int)(n + 1)];
 91     rest = new boolean[(const int)(n + 1)];
 92     g = MapManager(n, 2 * m);
 93     memset(rest, false, sizeof(boolean) * (n + 1));
 94     for(int i = 1, a, b; i <= m; i++) {
 95         readInteger(a);
 96         readInteger(b);
 97         g.addEdge(a, b);
 98     }
 99     for(int i = 1; i <= n; i++)
100         readInteger(moneys[i]);
101     readInteger(s);
102     readInteger(p);
103     for(int i = 1, a; i <= p; i++) {
104         readInteger(a);
105         rest[a] = true;
106     }
107 }
108 
109 int cnt = 0;
110 boolean *visited, *instack;
111 int* visitID, *exitID;
112 int *belong;
113 stack<int> st;
114 
115 inline void getPart(int end) {
116     int x;
117     do {
118         x = st.top();
119         st.pop();
120         instack[x] = false;
121         if(x != end) {
122             moneys[end] += moneys[x];
123             rest[end] = rest[x] || rest[end];
124         }
125         belong[x] = end;
126     } while(x != end);
127 }
128 
129 void tarjan(int node) {
130     visited[node] = instack[node] = true;
131     st.push(node);
132     visitID[node] = exitID[node] = ++cnt;
133     for(int i = m_begin(g, node); i != 0; i = g[i].next) {
134         int& e = g[i].end;
135         if(!visited[e]) {
136             tarjan(e);
137             smin(exitID[node], exitID[e]);
138         } else if(instack[e]) {
139             smin(exitID[node], visitID[e]);
140         }
141     }
142     if(visitID[node] == exitID[node])    getPart(node);
143 }
144 
145 MapManager ng;
146 inline void build() {
147     visited = new boolean[(const int)(n + 1)];
148     instack = new boolean[(const int)(n + 1)];
149     visitID = new int[(const int)(n + 1)];
150     exitID  = new int[(const int)(n + 1)];
151     belong  = new int[(const int)(n + 1)];
152     memset(visited, false, sizeof(boolean) * (n + 1));
153     memset(instack, false, sizeof(boolean) * (n + 1));
154     ng = MapManager(n, m);
155     tarjan(s);
156     for(int i = 1; i <= n; i++) {
157         for(int j = m_begin(g, i); j != 0; j = g[j].next) {
158             int& e = g[j].end;
159             if(belong[i] == belong[e])    continue;
160             ng.addEdge(belong[i], belong[e]);
161         }
162     }
163     delete[] instack;
164     delete[] visitID;
165     delete[] exitID;
166 }
167 
168 queue<int> que;
169 int *f;
170 inline void spfa() {
171     f = new int[(const int)(n + 1)];
172     memset(f, 0, sizeof(int) * (n + 1));
173     memset(visited, false, sizeof(boolean) * (n + 1));
174     que.push(belong[s]);
175     f[belong[s]] = moneys[belong[s]];
176     while(!que.empty()) {
177         int e = que.front();
178         que.pop();
179         visited[e] = false;
180         for(int i = m_begin(ng, e); i != 0; i = ng[i].next) {
181             int eu = ng[i].end;
182             if(belong[eu] != eu || belong[eu] == belong[e])    continue;
183             if(f[eu] < f[e] + moneys[eu]) {
184                 f[eu] = f[e] + moneys[eu];
185                 if(!visited[eu]) {
186                     que.push(eu);
187                     visited[eu] = true;
188                 }
189             }
190         }
191     }
192 }
193 
194 inline void solve() {
195     build();
196     spfa();
197     int res = 0;
198     for(int i = 1; i <= n; i++) {
199         if(belong[i] == i && rest[i]) {
200             smax(res, f[i]); 
201         } 
202     }
203     printf("%d", res);
204 }
205 
206 int main() {
207     init();
208     solve();
209     return 0;
210 }
posted @ 2017-03-22 20:41  阿波罗2003  阅读(320)  评论(0编辑  收藏  举报