codevs 1191 数轴染色 or 染色操作(ybt)

万年不上csdn,今天从自己的博客园搬一篇过来。
推销一下自己的博客园Mint的博客园

题面

image

###分析:
(1)先考虑暴力:直接每次在数组上暴力修改,复杂度O(n^2)级,估计也就30分
(2)这题属于区间修改和区间查询,可以考虑线段树,初始值全赋成1,修改操作就是将{l,r}之间的数-1,每次查询{1,n}的区间和就是剩余的黑色点数。不过线段树复杂度不够优秀,而且常数巨大,O(nlogn)也就能过
60~70。
(3)树状数组,常数小,但是复杂度和线段树一样,70估计没问题
(4)AC法:用并查集维护的链表加速修改,根据链表的性质,会跳过所有已经被修改过的点,因此每个点最多被处理一次,复杂度O(m+n),
为O(n)极,稳过100

####来深入理解一下链表吧
fa[i]表示i右侧(包括i自己)第一个黑色的点的编号
先给出一个初始的数列
image

现在我们修改{2,5}
image
下一次修改的时候,所有已经被修改的点就会被跳过,这就极大地加速了修改的速度,保证每个点最多只会被修改一次,复杂度O(n),非常优秀。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+40;
int fa[maxn],n,m,l,r; 
int Find(int x)
{ 
	if(fa[x]==x) return x;
	return fa[x]=Find(fa[x]);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n+1;i++) fa[i]=i; 
	for(int i=1;i<=m;++i)
	{
		scanf("%d%d",&l,&r);
		if(l>r) swap(l,r);
		while(1)
		{
			l=Find(l);
			if(l>r) break;
			else 
			{
				n--;
				fa[l]=l+1;	
			}
		}
		printf("%d\n",n);
	}
	return 0;
}	
对于链表的总结:我们常用链表,跳过已经被修改或去除的部分,以达到优化的效果。

tips:

关于并查集的部分还有一个很恶心的小细节:
每次我们修改链表的过程中,都会这样将l向右传递
看似没什么问题,但是当l==n时,且n为当前要修改的区间的右端点时,
l会继续向右走,直到l>n。
但是,每次我们这样传递l。

fa[l]=l+1

于是乎当l==n时,l会继续变成l+1(即n+1),但是按照一般的并查集初始化的习惯,我们只初始化到fa{n},因此fa{n+1}==0
此时l+1会进入下面这个语句

l=Find(l);

由于还有下面这个

int Find(int x)
{ 
	if(fa[x]==x) return x;
	return fa[x]=Find(fa[x]);
}

然后l就从n+1跳到了0,而fa{0}还是0,于是就陷入的无限循环中。
结果就爆栈了。

解决方法也不难:

(1)在循环中特判l=0不进入循环

while(1)
		{
			l=Find(l);
			if(l>r || l==0) break;
			else 
			{
				n--;
				fa[l]=l+1;	
			}
		}

(2)初始化到n+1,

fa[n+1]=n+1

(3)不初始化fa,由于fa是全局数组,因此初值为0,可理解成初值为0就是没有被修改
然后写成下面这个样子

int Find(int x)
{ 
	if(fa[x]!=0) return fa[x]=Find(fa[x]);
	//当fa[x]已经被更新时,向右寻找其他黑色的点
	return x;
	//当fa[x]没被更新时,x右侧第一个黑色的点一定是x自己
}

正确性:
Find(n+1)返回n+1,n+1>n因此会跳出循环,避免了死循环的情况。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值