bzoj 2936 [Poi 1999] 降水 - 并查集

题目传送门

  需要root权限的传送门

题目大意

  有一个$n\times m$的网格图,每一格都有一个高度。一次降雨过后问最多能积多少水。

  考虑算每一高度能储存的水的量。

  如果小于等于这个高度的格子和边界连通,那么水就会流走,这一部分不能算入答案。

  所以用并查集维护高度小于等于当前高度的格子的连通性。每次答案加已经找到的格子数目减去和边界连通的格子数。

  时间复杂度$O(nm + V)$。(用真·并查集就是这样)

  网上咋一群带个log的做法。想去loj出个加强版。

Code

 1 /**
 2  * bzoj
 3  * Problem#2936
 4  * Accepted
 5  * Time: 56ms
 6  * Memory: 1688k 
 7  */
 8 #include <bits/stdc++.h>
 9 using namespace std;
10 typedef bool boolean;
11 
12 const int N = 105, V = 10000;
13 const int mov[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
14 
15 typedef class Dsu {
16     public:
17         int *f;
18         int *siz;
19 
20         Dsu() {    }
21         Dsu(int n) {
22             f = new int[(n + 1)];
23             siz = new int[(n + 1)];
24             f[0] = siz[0] = 0; 
25             for (int i = 1; i <= n; i++)
26                 f[i] = i;
27             for (int i = 1; i <= n; i++)
28                 siz[i] = 1;
29         }
30 
31         int find(int x) {
32             return (f[x] == x) ? (x) :(f[x] = find(f[x]));
33         }
34 
35         void unit(int x, int y) {
36             int fx = find(x);
37             int fy = find(y);
38             if (fx == fy)
39                 return;
40             siz[fy] += siz[fx];
41             f[fx] = fy;
42         }
43 }Dsu;
44 
45 int n, m;
46 Dsu uf;
47 boolean found[N][N];
48 vector< pair<int, int> > vs[V + 1];
49 
50 int id(int x, int y) {
51     if (!x || !y || x == n + 1 || y == m + 1)
52         return 0;
53     return (x - 1) * m + y;
54 }
55 
56 inline void init() {
57     scanf("%d%d", &n, &m);
58     uf = Dsu(n * m);
59     for (int i = 1; i <= n; i++)
60         for (int j = 1, h; j <= m; j++) {
61             scanf("%d", &h);
62             vs[h].push_back(pair<int, int>(i, j));
63         }
64 }
65 
66 int cfound = 0, res = 0;
67 inline void solve() {
68     int all = n * m;
69     for (int v = 1; v <= V && uf.siz[uf.find(0)] != all; v++) {
70         for (int j = 0; j < (signed) vs[v].size(); j++) {
71             int x = vs[v][j].first, y = vs[v][j].second;
72             found[x][y] = true, cfound++;
73             for (int k = 0; k < 4; k++) {
74                 int nx = x + mov[k][0], ny = y + mov[k][1], nxid = id(nx, ny);
75                 if (!nxid || found[nx][ny])
76                     uf.unit(nxid, id(x, y));
77             }
78         }
79         res += cfound - uf.siz[uf.find(0)];
80     }
81     printf("%d", res);
82 }
83 
84 int main() {
85     init();
86     solve();
87     return 0;
88 }
posted @ 2018-08-05 10:38  阿波罗2003  阅读(416)  评论(0编辑  收藏  举报