zoukankan      html  css  js  c++  java
  • bzoj 2936 [Poi 1999] 降水

    题目传送门

      需要root权限的传送门

    题目大意

      有一个$n imes 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 }
  • 相关阅读:
    C语言 sprintf 函数 C语言零基础入门教程
    C语言 printf 函数 C语言零基础入门教程
    C语言 文件读写 fgets 函数 C语言零基础入门教程
    C语言 文件读写 fputs 函数 C语言零基础入门教程
    C语言 fprintf 函数 C语言零基础入门教程
    C语言 文件读写 fgetc 函数 C语言零基础入门教程
    C语言 文件读写 fputc 函数 C语言零基础入门教程
    C语言 strlen 函数 C语言零基础入门教程
    Brad Abrams关于Naming Conventions的演讲中涉及到的生词集解
    适配器模式
  • 原文地址:https://www.cnblogs.com/yyf0309/p/9424730.html
Copyright © 2011-2022 走看看