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

题目传送门

  需要root权限的传送门

题目大意

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

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

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

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

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 }

原文地址:https://www.cnblogs.com/yyf0309/p/9424730.html

时间: 2024-08-05 10:04:15

bzoj 2936 [Poi 1999] 降水 - 并查集的相关文章

BZOJ 3562: [SHOI2014]神奇化合物 并查集+dfs

点击打开链接 注意到20w条边,但是询问只有1w,所以有很多边是从头到尾不变的. 首先离线处理,将从未删除的边缩点,缩点后的图的点数不会超过2w,对于每一次add或者delete,直接dfs看是否能从a走到b,然后维护一个ans. 数据不强,不然这种复杂度起码要跑10s.. #include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> using namespace st

bzoj 2733 永无乡 - 并查集 - 线段树

永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的.现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥.Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪 座,请你输

【BZOJ 3674】可持久化并查集加强版&amp;【BZOJ 3673】可持久化并查集 by zky 用可持久化线段树破之

最后还是去掉异或顺手A了3673,,, 并查集其实就是fa数组,我们只需要维护这个fa数组,用可持久化线段树就行啦 1:判断是否属于同一集合,我加了路径压缩. 2:直接把跟的值指向root[k]的值破之. 3:输出判断即可. 难者不会,会者不难,1h前我还在膜这道题,现在吗hhh就当支持下zky学长出的题了. 3673: #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=ge

BZOJ 1116 [POI2008]CLO(并查集)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1116 [题目大意] Byteotia城市有n个towns,m条双向roads.每条road连接两个不同的towns, 没有重复的road.你要把其中一些road变成单向边使得:每个town都有且只有一个入度 [题解] 我们发现当一个连通块边数大于等于其点数的时候就满足条件, 那么此题如果出现边数少于点数的连通块就不成立, 用并查集能够完成判断. [代码] #include <cstd

bzoj 1455 可并堆+并查集

一个堆和一个并查集对应,并且满足并查集中所有没有死的人等于堆中的人 1 /************************************************************** 2 Problem: 1455 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:2688 ms 7 Memory:32336 kb 8 *************************************************

【BZOJ】3673: 可持久化并查集 by zky &amp; 3674: 可持久化并查集加强版(可持久化线段树)

http://www.lydsy.com/JudgeOnline/problem.php?id=3674 http://www.lydsy.com/JudgeOnline/problem.php?id=3673 双倍经验啦啦啦.. 给主席树换了个名称果然高大上... 首先要可持久化并查集其实就是可持久化数组... 那么因为数组的形式是这样的$P[x]$,那么我们用一种数据结构实现查找x返回对应的$P[x]$即可啦啦啦. 然后那么我所学的可持久化目前只有主席树QAQ哪天去写写fhqtreap...

BZOJ 1821 部落划分(二分+并查集)

答案是具有单调性的. 因为最近的两个部落的距离为mid,所以要是有两个野人的距离<mid,则他们一定是一个部落的. 用并查集维护各联通块,如果最后的联通块个数>=k,那么mid还可以再小点.如果<k,mid还可以再大点. 二分搞一搞就行了. # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector&

bzoj 1191: [HNOI2006]超级英雄Hero 并查集 || 匈牙利算法

1191: [HNOI2006]超级英雄Hero Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1804  Solved: 850[Submit][Status] Description 现在电视台有一种节目叫做超级英雄,大概的流程就是每位选手到台上回答主持人的几个问题,然后根据回答问题的多少获得不同数目的奖品或奖金.主持人问题准备了若干道题目,只有当选手正确回答一道题后,才能进入下一题,否则就被淘汰.为了增加节目的趣味性并适当降低难度,主持人总

BZOJ 4195: [Noi2015]程序自动分析 [并查集 离散化 | 种类并查集WA]

题意: 给出若干相等和不等关系,判断是否可行 woc NOI考这么傻逼的题飞快打了一个种类并查集交上了然后爆零... 发现相等和不等看错了异或一下再叫woc90分 然后发现md$a \neq b, a \neq c,不能得到b = c$ 老老实实的把所有相等关系加并查集然后不等关系来判断吧,唉 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using