[ SCOI 2016 ] 萌萌哒

题目

Luogu
LOJ
Acwing

思路

1.png
2.png
3.png
4.png

代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010, mod = 1e9 + 7;
int n, m, f[N][20];
// k 是倍增自带的, 忽略 k 就和普通并查集一模一样了
int find(int x, int k) { return f[x][k] != x ? (f[x][k] = find(f[x][k], k)) : f[x][k]; }
void merge(int x, int y, int k) { f[find(x, k)][k] = f[find(y, k)][k]; }
int main() {
    cin >> n >> m;
    for (int j = 0; j <= 19; j++)
        for (int i = 1; i <= n; i++)
            f[i][j] = i;
    for (int a, b, c, d; m-- && cin >> a >> b >> c >> d; )
        for (int i = 19; i >= 0; i--)
            if (a + (1 << i) - 1 > b) continue; // 比右边区间大的就跳过
            else merge(a, c, i), a += 1 << i, c += 1 << i; // 倍增跳
    for (int j = 20; j >= 1; j--) // 注意 >= 1
        for (int i = 1; i + (1 << j) - 1 <= n; i++)
            merge(i, find(i, j), j - 1),  // 推到两个子区间
            merge(i + (1 << (j - 1)), find(i, j) + (1 << (j - 1)), j - 1);
    int cnt = 0, res = 9;
    for (int i = 1; i <= n; i++) cnt += (f[i][0] == i); // 判断几个集合
    for (int i = 1; i <= cnt - 1; i++) res = 1ll * res * 10 % mod; // 暴力算就行
    cout << res << endl;
    return 0;
}
posted @ 2021-04-16 18:25  Protein_lzl  阅读(63)  评论(0编辑  收藏  举报