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 }