[SCOI2016]萌萌哒
Description
Solution
一个非常naive的想法就是并查集暴力维护哪些集合要填一样的数,最后统计有几个集合就行了。但是这样是\(O(n^2)\)的。
可以借鉴ST表的思想,每次只合并两个区间,然后下传同类关系就行。
Code
#include <cstdio>
#include <cstring>
#include <queue>
typedef long long ll;
const int N = 1e5 + 10;
const ll mod = 1e9 + 7;
int fa[20][N], n, m, sz[20][N], L2[N];
int find(const int &lvl, const int &x) {
return fa[lvl][x] == x ? x : fa[lvl][x] = find(lvl, fa[lvl][x]);
}
void merge(const int &lvl, const int &x, const int &y) {
int fx = find(lvl, x), fy = find(lvl, y);
if (fx == fy) return;
if (sz[lvl][fx] > sz[lvl][fy])
fa[lvl][fy] = fx;
else
fa[lvl][fx] = fy;
if (sz[lvl][fx] == sz[lvl][fy]) sz[lvl][fy]++;
return;
}
ll pow_mod(ll x, int p) {
ll ans = 1;
for (; p; p >>= 1, x = x * x % mod)
if (p & 1) ans = ans * x % mod;
return ans;
}
int main() {
scanf("%d%d", &n, &m);
int l1, r1, l2, r2;
for (int i = 2; i <= n; ++i) L2[i] = L2[i >> 1] + 1;
for (int i = 0; i <= L2[n] + 1; ++i)
for (int j = 1; j <= n; ++j) fa[i][j] = j;
for (int i = 1; i <= m; ++i) {
scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
int len = L2[r1 - l1 + 1];
merge(len, l1, l2);
merge(len, r1 - (1 << len) + 1, r2 - (1 << len) + 1);
}
for (int i = L2[n] + 1; i; --i) {
for (int j = 1; j <= n; ++j) {
merge(i - 1, j, find(i, j));
if (j + (1 << i - 1) <= n)
merge(i - 1, j + (1 << i - 1), find(i, j) + (1 << i - 1));
}
}
int cnt = 0;
for (int i = 1; i <= n; ++i)
if (fa[0][i] == i) cnt++;
printf("%lld\n", pow_mod(10LL, cnt - 1) * 9 % mod);
return 0;
}