P3295 [SCOI2016]萌萌哒
description
solution
强制部分区间相同,很容易就想到了并查集,直接暴力并查集合并是O(n2)O(n^2)O(n2)的
只需要考虑那一个数据结构将其转化成O(nlogn)O(n\log n)O(nlogn)的
树之类的就不考虑了,一段一段的区间——倍增啊!
将点iii拆成logloglog个点
fi,j:f_{i,j}:fi,j: 仅考虑[i,i+2j)[i,i+2^j)[i,i+2j)段内的数
最后进行fff并查集的标记下放合并
最后则是9∗10cnt−1,cnt9*10^{cnt-1},cnt9∗10cnt−1,cnt表示不同的并查集数量,首不能为000
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;
}