Loading

编程入门题瞎做(一)

luogu P3295 [SCOI2016]萌萌哒

题目链接

这里的计数没有任何的技术含量,当你知道那几个位置必须一样后,就疯狂乘 \(10\) 就可以了。

现在问题是怎么找到那几个位置必须一样。
考虑一种最暴力的方法,对于任意 \(i\ (0\leq i\leq r_1-l_1+1)\) 我们把 \(i+l_1\)\(i+l_2\) 用并查集并起来。
最后显然一个集合内的位置都是相同的颜色。这样做的时间复杂度是 \(O(n^2\log n)\)

考虑怎么优化,想到之前学的线段树优化建图,发现不需要进行实时修改,直接用 \(\tt ST\) 表就可以了。
我们定义 \(fa(i,j)\) 表示 \([i,i+2^j-1]\) 这段区间内的根 的左端点。
也就是说我们把并查集做一个类似倍增的方法,它的父亲对应的也是一段区间,为了方便我们钦定它的父亲为根的左端点。
合并的话跟倍增几乎时一模一样。

注意到最后要把所有的相同位置拉入到一个集合,也就是对于每一层,都要和它的上一层合并。
具体的可以看一下代码。

点击查看代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>

#define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)

const int N = 1e5 + 5;
const int mod = 1e9 + 7;

int n, m, lg[N];

namespace UFST {
int fa[N][20];
inline int find(int x, int k);
inline void merge(int a, int b, int k);
}
using UFST::fa;

signed main(void) { 
  read(n, m);
  for (int i = 1, l1, l2, r1, r2; i <= m; i++) {
    read(l1, r1, l2, r2);
    node[i] = Node(l1, r1, l2, r2);
  }
  for (int i = 1; i <= n; i++)
    for (int j = 0; j <= 20; j ++) fa[i][j] = i;
  for (int i = 1, l1, r1, l2, r2; i <= m; i++) {
    l1 = node[i].l1, r1 = node[i].r1, l2 = node[i].l2, r2 = node[i].r2;
    for (int j = 20; j >= 0; j --) 
      if (l1 + (1 << j) - 1 <= r1) {
        UFST::merge(l1, l2, j);
        l1 += 1 << j; l2 += 1 << j;
      }
  }
  for (int j = 20; j >= 1; j--) {
    for (int i = 1; i + (1 << j) - 1 <= n; i++) {
      int pos = UFST::find(i, j);
      UFST::merge(i, pos, j - 1);
      UFST::merge(i + (1 << j - 1), pos + (1 << j - 1), j - 1);
    }
  }
  int ans = 0;
  for (int i = 1; i <= n; i++)
    if (fa[i][0] == i) {
      if (ans == 0) ans = 9;
      else ans = 1ll * ans * 10 % mod;
    }
  std::cout << ans << std::endl;
  return 0;
}

namespace UFST {
inline int find(int x, int k) {
  if (fa[x][k] == x) return x;
  return fa[x][k] = find(fa[x][k], k);
}
inline void merge(int a, int b, int k) {
  a = find(a, k); b = find(b, k);
  if (a == b) return ;
  fa[a][k] = b;
}
}
posted @ 2022-08-14 14:28  Aonynation  阅读(28)  评论(0编辑  收藏  举报