分块
是一种暴力结构
给定一个序列a,q个询问,求区间[L,R]权值和。
显然树状数组,线段树等结构都可做
没有学习它们的时候我们是如何解决这个问题的?
前缀和
那么再加上更新
如果不借助上述数据结构只能暴力维护
for(int i=l;i<=r;++i)a[i]+=data;
for(int i=l;i<=r;++i)ans+=a[i]
之所以成分块是暴力数据结构正是因为分块就是建立在暴力的基础之上的。
分块的核心思想是大段维护,小段暴力
把长度为n的序列分成块长(block)为sqrt(n)的若干块(cnt=n/block)。每一个快都有一个边界l,r,通过数学归纳法可以得出
for(int i=1;i<=cnt;++i){
p[i].l=(i-1)*block+1;
p[i].r=i*block;
}
但是由于分块题经常卡常,用加法代替相对低效的乘法,通常写成这种形式
for(int i=1;i<=cnt;++i){
p[i].l=p[i-1].r+1;
p[i].r=p[i].l+block-1;
}
块里可以维护很多东西,如果要维护的元素不能实现区间的直接转移(也就是传统数据结构不能解决),比如说a在区间中出现的次数,那么分块就是较好的选择
这里维护块中所有元素的和,以及一个lazytag(借鉴线段树的思想,用到的时候再下放)。
更新操作
int bl=belong[l],br=belong[r];
if(bl==br){//在一个块内暴力
for(int i=l;i<=r;++i){
a[i]+=data;
}
}
else{
for(int i=l;i<=p[bl].r;++i){//不是整块暴力
a[i]+=data;
}
for(int i=p[br].l;i<=r;++i){
a[i]+=data;
}
for(int i=bl+1;i<=br-1;++i){
p[i].add+=data;//懒标记
}
}
查询操作
int bl=belong[l],br=belong[r];
if(bl==br){//在一个块内暴力
for(int i=l;i<=r;++i){
sum+=a[i];
}
return sum;
}
else{
for(int i=l;i=p[bl].r;++i){
if(p[bl].add){
sum+=p[bl].add;
}
sum+=a[i];
}
for(int i=p[br].l;i<=r;++i){
if(p[br].add){
sum+=p[br].add;
}
sum+=a[i];
}
for(int i=bl+1;i<=br-1;++i){
sum+=p[i].data+p[i].add;
}
}
时间复杂度(块数)
分块能解决的问题:
1.RMQ,区间权值和等
2.维护区间众数 例题:蒲公英
3.区间中第k小的元素 对每个块排序,然后二分查找下标 例题:教主的魔法
4.以及各种东西 例题:弹飞绵羊
分块题目和传统数据结构题相似,考虑如何预处理,如何查询,如何更新
(这是句废话)
可以通过数学证明得到最佳块长实际上为pow(n,2.0/3),时间复杂度由原来的O(n*sqrt(n)),变为O(n^5/3)
标签:暴力,分块,int,belong,bl,br,莫队 来源: https://www.cnblogs.com/Chano/p/16265425.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。