P3295 [SCOI2016]萌萌哒(DP+倍增)

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 910cnt1,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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值