也许有卵用的东西

其实就是打暴力

在处理某些区间问题时,要维护的信息不具有比较方便维护的性质,因此无法用线段树等维护,此时可以使用分块骗分解决

基本分块

操作:建块,暴力维护,没了
线段树最朴素的区间加,区间查用分块实现的话就差不多是模板了

	len=sqrt(n),num=n/len;if(n%len)num++;
	for(int i=1;i<=num;i++)
	{	
		ll[i]=(i-1)*len+1,rr[i]=ll[i]+len-1;
		if(i==num)rr[i]=n;
		for(int j=ll[i];j<=rr[i];j++)sum[i]+=a[j],bl[j]=i;
	}

主要是建块,确定左右端点以及每个原序列的位置属于哪一个块

弹飞绵羊

分块之后维护跳到下一个块的步数,这样每次修改就是根号的
基本上就是看着什么能分块,一般是原序列,看以块为单位怎么维护信息

教主的魔法

分块,块内进行排序,二分查找,因为数据不大所以复杂度没有问题
分块可以搭配其他算法,比如二分,排序这些基础的,或者更高级的数据结构

蒲公英

这个用的蓝书上写法,可能不是很优秀,因为正解是严格\(n\sqrt n\)
预处理整块信息,散块在值域vector里二分求
分块很多操作都是在值域上进行的,所以值域一般不会很大,大了就离散化

颜色

这个应该是预处理的终极应用了
分别预处理\(l,r\)块内的整块信息,具体的就是平方和和颜色个数
然后查询就可以整块直接出,散块暴力
一般块长是根号,但这个是算出来的,用均值算一下啥时候最优,还有空间问题
每次在值域数组里加上贡献,然后答案加上贡献(这个要算一下),如果清空要一个一个清

莫队

分块的另一种形式,即对询问分块
我们暴力处理询问的一种方式是维护两个指针在序列上,每次让指针去覆盖询问区间,多加少减,两个指针中间就是当前答案
发现复杂度主要浪费在指针移动上,因为来回移动所以没保证,尝试对询问排序使移动次数尽量少
如果左端点在一个块里就按照右端点从大到小排序,否则按照左端点从从小到大排序
本质就是使询问有了一定的单调性,有证明这样总复杂度就是\(n\sqrt n\) ,可以利用奇偶性优化常数

while(l>q[i].l)add(--l);
while(r<q[i].r)add(++r);
while(l<q[i].l)de(l++);
while(r>q[i].r)de(r--);

指针移动循环顺序较为关键,在24种写法中只有6种对,这里记一个正确的

小B的询问

裸莫队,按需要维护即可

小Z的袜子

推一下式子发现总数是\(\sum sum_c\times (sum_c-1)/2\),那么一个答案就是\(ans/ \dbinom{r-l+1}{2}\)然后直接上莫队

作业

对于询问用莫队处理,找到对应的区间正确维护出每种颜色出现的次数
对值域分块来统计答案,复杂度依然为根号,没有问题

带修莫队

莫队加时间轴,端点不在一块内的按照修改时间排序,移动指针的时候多移动个时间指针
这个块长取三分之二是最优的,总体在\(n^{5/3}\)状态

回滚莫队

当莫队不好删除的时候用这个,把左端点在一块的询问按照右端点排序
右指针单调可以一直走,左指针处理完应该询问直接回到出发点,块长根号那么复杂度依旧是\(n\sqrt n\)
用栈记录数组里的变化,每次还原回去,答案不好还原就不还原,直接重新记,反正每次是爆扫

总结

基本当骗分利器学习,顺便锻炼下码力,太难的也不会
在有时间的时候确实是一种比暴力优的策略,前提是各种操作要熟练
还是暴力好使

予明日所有失败者 赋万千不灭颂歌