P3295 [SCOI2016]萌萌哒
description
solution
强制部分区间相同,很容易就想到了并查集,直接暴力并查集合并是
O
(
n
2
)
O(n^2)
O(n2)的
只需要考虑那一个数据结构将其转化成
O
(
n
log
n
)
O(n\log n)
O(nlogn)的
树之类的就不考虑了,一段一段的区间——倍增啊!
将点
i
i
i拆成
l
o
g
log
log个点
f
i
,
j
:
f_{i,j}:
fi,j: 仅考虑
[
i
,
i
+
2
j
)
[i,i+2^j)
[i,i+2j)段内的数
最后进行
f
f
f并查集的标记下放合并
最后则是
9
∗
1
0
c
n
t
−
1
,
c
n
t
9*10^{cnt-1},cnt
9∗10cnt−1,cnt表示不同的并查集数量,首不能为
0
0
0
code
#include <cstdio>
#define mod 1000000007
#define int long long
#define maxn 100005
int n, m, cnt;
int f[maxn][20];
int qkpow( int x, int y ) {
int ans = 1;
while( y ) {
if( y & 1 ) ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans;
}
void make() {
for( int i = 1;i <= n;i ++ )
for( int j = 0;j < 20;j ++ )
f[i][j] = i;
}
int find( int i, int j ) {
return i == f[i][j] ? i : f[i][j] = find( f[i][j], j );
}
void merge( int i, int k, int j ) {
if( find( i, j ) == find( k, j ) ) return;
else f[f[i][j]][j] = f[k][j];
}
signed main() {
scanf( "%lld %lld", &n, &m );
make();
for( int i = 1, l, r, L, R;i <= m;i ++ ) {
scanf( "%lld %lld %lld %lld", &l, &r, &L, &R );
for( int j = 19;~ j;j -- )
if( l + ( 1 << j ) - 1 <= r ) {
merge( l, L, j );//给一整段都打上标记
l += ( 1 << j );
L += ( 1 << j );
}
}
for( int j = 19;j;j -- )
for( int i = 1;i + ( 1 << j ) - 1 <= n;i ++ ) {//标记下放
merge( i, find( i, j ), j - 1 );
merge( i + ( 1 << j - 1 ), f[i][j] + ( 1 << j - 1 ), j - 1 );
}
int tot = 0;
for( int i = 1;i <= n;i ++ )
if( find( i, 0 ) == i ) tot ++;
printf( "%lld\n", qkpow( 10, tot - 1 ) * 9 % mod );
return 0;
}