题解 P3295 【[SCOI2016]萌萌哒】

文章讲述了在SCOI2016竞赛中如何使用并查集处理问题,通过逆用st表优化约束条件的合并操作,利用懒标记和线段树思想降低时间复杂度,最后介绍并查集的合并策略,包括倍增过程。
摘要由CSDN通过智能技术生成

 先引用一下这位大佬的题解,对此我再进行细化

题解 P3295 【[SCOI2016]萌萌哒】 - 洛谷专栏icon-default.png?t=N7T8https://www.luogu.com.cn/article/it7foeu6并查集

首先是如何想出来需要并查集处理,下面是n=8,第一组约束条件是[1,4]和[5,8],如下图,那么

对应位置就应该是[1->5]  [2->6]......这些位置的数字是相同的,就相当于捆绑在一起了,回想并查集就是将具有相同特征的放在一个集合里(具有相同的根),于是我们这里便可以开四个并查集。

逆用st表

引出st表

对上述约束,在添加一条[1,2],[3,4]相等的约束,由于上一条3和7数字相同..那么这个时候3和1相同,那么7和1也应该相同,所以应该对其并查集进行合并,合并到1号这个并查集上,8号合并到2号上,考虑到更改,如果直接改,那就要遍历整段数,对其更改,例如n=32,每次取[1,16] [17,32]....[1,8] [9,16],依次类推,更新的时候就麻烦了,可以自己画个图看一下,时间复杂度n*m,是不可接受的,于是我们考虑是否可以在在某个位置打上标记,等修改结束后,在单独遍历一遍,然后对其更新,类似于线段树懒标记的思想。

然后就是对st表的逆应用

我们在选择标记(merge合并)的时候,首先第一步先把当前能跳的最大的位置个标记上,然后再从当前位置选择继续能跳到最大的位置进行标记。当标记完了之后,我们再对有标记的节点直接的节点打上标记,然后我们选择区间的中点进行,相当与反倍增了。倍增是从两段获取一段,这里是从一段返回去获得两段。如果还不理解可以打个表看看就明白了(就是输出当前f[i][j])。

for(int j=mx;j>=1;j--){
		for(int i=1;i+(1<<j)-1<=n;i++){
			int p=find(i,j);
			merge(i,p,j-1),merge(i+(1<<(j-1)),p+(1<<(j-1)),j-1);
		}
	}	

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值