USACO20JAN Cave Painting 【并查集】

一开始我想的是从地图中弄出一个森林来,这样确实可行,但是太麻烦了

事实上,我们并不一定需要把建出来

从最低海拔往上统计答案,考虑当两个联通合并会对答案造成什么影响:新的联通块的方案数为两个联通块的乘积(或者说所有合并了的联通块的乘积,因为有可能有多个联通块合并),当这一层计算完后,再给这一层的块的答案加一,表示全部都有水的情况

使用并差集来维护联通块就行了

统计最终时,我们把不同联通块的答案乘起来从而得到最终的答案

注意需要开long long

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define gi get_int()
#define int long long
const int MAXN = 1001 * 1001;
const int MOD = 1e9 + 7;
int get_int()
{
  int x = 0, y = 1;
  char ch = getchar();
  while (!isdigit(ch) && ch != '-')
    ch = getchar();
  if (ch == '-') 
    y = -1, ch = getchar();
  while (isdigit(ch))
    x = x * 10 + ch - '0', ch = getchar();
  return x * y;
}

int map[1001][1001], vis[MAXN], toBeAdd[MAXN];
int fa[MAXN], val[MAXN];
long long ans = 1;

int getFa(int u)
{ 
  return fa[u] == u ? u : fa[u] = getFa(fa[u]);
}

int getPos(int x, int y)
{
  return x * 1001 + y;
}

signed main()
{
  int n = gi, m = gi;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      char ch;
      std::cin >> ch;
      if (ch == '#')
        map[i][j] = -1;
      if (ch == '.')
        map[i][j] = 1;
    }
  }
  for (int i = 0; i < MAXN; i++)
    fa[i] = i, val[i] = 1;;
  for (int i = n - 2; i >= 0; i--) {
    /*
    int cnt = 0, flag = 0;
    for (int j = 0; j < m; j++) {
      if (map[i + 1][j] == -1 && flag == 1) {
        if (cnt == 0 && vis[getFa(getPos(i + 1, j - 1))] == 0) {
          getAns(getPos(i + 1, j - 1));
          std::cout << i + 2 << ' ' << j << std::endl;
          vis[getFa(getPos(i + 1, j - 1))] = 1;
        }
        cnt = 0;
        flag = 0;
      }
      if (map[i + 1][j] == 1)
        flag = 1;
      if (map[i][j] == 1 && map[i + 1][j] == 1)
        cnt++;
    }
    */
    for (int j = 1; j < m; j++) {
      if (map[i][j] == -1) continue;
      if (map[i][j - 1] == 1) {
        int u = getFa(getPos(i, j)), v = getFa(getPos(i, j - 1));
        fa[v] = u;
      }
    }
    int tmp = 0;
    for (int j = 1; j < m; j++) {
      if (map[i][j] == -1) continue;
      if (map[i + 1][j] == 1) {
        int u = getFa(getPos(i, j)), v = getFa(getPos(i + 1, j));
        if (u == v) continue;
        fa[v] = u;
        (val[u] = val[u] * val[v]) %= MOD;
      }
    }
    for (int j = 1; j < m; j++) {
      if (map[i][j] == -1) continue;
      if (toBeAdd[getFa(getPos(i, j))] == 1) continue;
      toBeAdd[getFa(getPos(i, j))] = 1;
      val[getFa(getPos(i, j))]++;
    }
    for (int j = 1; j < m; j++) {
      if (map[i][j] == -1) continue;
      toBeAdd[getFa(getPos(i, j))] = 0;
    }
  }
  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++) {
      int now = getFa(getPos(i, j));
      if (vis[now] == 1) continue;
      vis[now] = 1;
      (ans *= val[now]) %= MOD;
      //std::cout << val[now] << std::endl;
    }
  std::cout << ans;
  return 0;
}
上一篇:1001系列之案例0002如何从斯德哥尔摩气温数据集中可视化挖掘


下一篇:1001 害死人不偿命的(3n+1)猜想