关于分块和莫队

关于分块, 我认为没有什么可说的, 只需要背会模板,看情况拓展即可。 而关于莫队, 请参考以下博客:某大佬博客
和分块一样,莫队是一种偏暴力的算法,很可能会遇到卡常等问题,一下介绍两个没有本质作用的优化。

1.分块大小

image
带修莫队时:
image
但这些分块大小遇到P1903 [国家集训队]数颜色 / 维护队列这道题通通TLE, 而我把块的大小定义成一个常数2021时, 发现程序跑的飞快, 64→100,所以当遇到卡常时不妨换个块的大小,说不定有奇迹发生

2.奇偶性排序

在排序时,我们还可以加入一个奇偶性的排序优化,对于正常的排序,应该是这样的:

inline bool compare(query p1,query p2)
{
	if ( (p1.l/size) ^ (p2.l/size) )
	return p1.l < p2.l ;
	else return p1.r < p2.r;
}

考虑到左端点在同一块中,我们是按右端点升序排序的,显然在做完一块的所有左端点后,区间的右端点也被移到了整个序列的后方,
而在下一个块的开始,右端点又是从小到大排序的,这样右端点就要从序列的较后方跑到序列的较前方,这样是很费时间的。

所以我们考虑排序时将第二关键字右端点的排序方式按照块的奇偶性来决定,也就是说,右端点一次升序一次降序,轮流来,就减少了上述的耗时移动。

inline bool compare(query p1,query p2)
{
	if ( (p1.l/size) ^ (p2.l/size) )
	return p1.l < p2.l ;
	else if ( (p1.l/size) & 1 )
	return p1.r < p2.r ;
	else return p1.r > p2.r ;
}

理论上,这种排序方法是有1/2的小常数的。

3.玄学优化

这个就靠仙术和自己的运气了,

//		while (R > r) add(++r);
//		while (L < l) add(--l);
//		while (R < r) del(r--);
//		while (L > l) del(l++);
		while(l < L) w -= !--cnt[a[l++]];
		while(l > L) w += !cnt[a[--l]]++;
		while(r < R) w += !cnt[a[++r]]++;
		while(r > R) w -= !--cnt[a[r--]];

将函数简化是一种很不错的方法
以及inline, register, 必要时吸一波氧气:#pragma GCC optimize(2)嘤嘤嘤

posted @ 2021-09-14 15:41  海边微风起  阅读(50)  评论(0编辑  收藏  举报