题意:维护一个数列,给出维护区间加法,询问区间内大于等于某个值的元素个数。

算法:分块。因为本题第二问显然可以用二分的思想,但是这貌似并不符合区间可加性,线段树好像就不好用了呢。所以本蒟蒻学习了分块。

这大概是本蒟蒻的第一题正式分块,思想是在hzwer学长的分块入门学的==。

什么是分块?我们维护数列(貌似树上也可以)信息时可以先采用分治的思想,把数列分成若干连续的块,维护信息可以统一在块上进行维护。假如有一个n元素的数列,根据均值不等式的数学知识(并不会证明),我们把每个块的大小设为根号n可以达到最右效果。但是显然有时根号n并不是整数==,没有关系,我们的数列上大部分都在整块上,只有小部分被遗弃的元素在不完整的块中。

我们进行区间操作时,把在整块中的元素进行整体操作,那些在不完整的块中的元素进行暴力操作

总结来说,就是“大块维护,小段朴素”,这也是分块最基本的思想。

分块的复杂度(根号算法)虽然较其他数据结构可能略高了一些,却是打暴力的好方法,思维较简单,处理问题的范围更广,码量...可能略大(?)

回到本题的两个操作:

区间加法:对于一段区间,如果存在被整块覆盖的情况,直接在整块的加法标记上记录,不需在原序列上改动,查询时在加上加法标记;而在不完整的块中的元素,直接暴力修改。

查询大于等于X的元素个数:想一想如果数列是无序的,我们分的块就完全没用了。但是如果我们在预处理时以及修改时对每个整块进行排序,查询时调用lower_bound/手写二分查找,问题就能轻松得到解决。那些在不完整块中的元素,同理,暴力枚举统计。

综上,我们不难发现,使用分块算法需要或者只需要想的两个关键:

  怎么维护整块?怎么维护不完整的块?

分块的更多代码实现细节:

  (几乎每到分块题都要的)bl[i]记录i在第几个块

  bl[i]*blo(blo=sqrt(n))可以得出当前位置(块的右边界),在此基础上变形

  右边界:取min,bl[l]*blo,n(防止越界)

Code

 // luogu-judger-enable-o2
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector> using namespace std; int n,Q,blo;
int val[],bl[],addtag[];
char opt[];
vector<int>cnt[]; void update(int x)
{
cnt[x].clear();
for(int i=(x-)*blo+;i<=min(x*blo,n);i++)
cnt[x].push_back(val[i]);
sort(cnt[x].begin(),cnt[x].end());
} void add(int l,int r,int p)
{
if(l==r) val[l]+=p;
else
{
for(int i=l;i<=min(bl[l]*blo,r);i++)
val[i]+=p;
update(bl[l]);
if(bl[l]!=bl[r])
{
for(int i=(bl[r]-)*blo+;i<=r;i++)
val[i]+=p;
update(bl[r]);
}
for(int i=bl[l]+;i<=bl[r]-;i++)
addtag[i]+=p;
}
} int query(int l,int r,int p)
{
int ans=;
for(int i=l;i<=min(bl[l]*blo,r);i++)
if(val[i]+addtag[bl[l]]>=p) ans++;
if(bl[l]!=bl[r])
{
for(int i=(bl[r]-)*blo+;i<=r;i++)
if(val[i]+addtag[bl[r]]>=p) ans++;
}
for(int i=bl[l]+;i<=bl[r]-;i++)
{
int tmp=p-addtag[i];
int pos=lower_bound(cnt[i].begin(),cnt[i].end(),tmp)-cnt[i].begin();
ans+=blo-pos;
// ans+=find(i,tmp);
}
return ans;
} int main()
{
scanf("%d%d",&n,&Q);
for(int i=;i<=n;i++) scanf("%d",&val[i]);
blo=sqrt(n);
for(int i=;i<=n;i++)
{
bl[i]=(i-)/blo+;
cnt[bl[i]].push_back(val[i]);
}
for(int i=;i<=bl[n];i++)
sort(cnt[i].begin(),cnt[i].end());
while(Q--)
{
scanf("%s",opt+);
int x=,y=,z=;
scanf("%d%d%d",&x,&y,&z);
if(opt[]=='M')
add(x,y,z);
else if(opt[]=='A')
printf("%d\n",query(x,y,z));
}
return ;
}

代码纯享版

 // luogu-judger-enable-o2
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector> using namespace std; int n,Q,blo;
int val[],bl[],addtag[];
char opt[];
vector<int>cnt[]; void update(int x)//针对散块
{//清空,重新读入
cnt[x].clear();
for(int i=(x-)*blo+;i<=min(x*blo,n);i++)
cnt[x].push_back(val[i]);
sort(cnt[x].begin(),cnt[x].end());
} void add(int l,int r,int p)
{
if(l==r) val[l]+=p;
else
{
for(int i=l;i<=min(bl[l]*blo,r);i++)
val[i]+=p;//左散块
update(bl[l]);//重新排序
if(bl[l]!=bl[r])
{//右散块
for(int i=(bl[r]-)*blo+;i<=r;i++)
val[i]+=p;
update(bl[r]);
}
//整块
for(int i=bl[l]+;i<=bl[r]-;i++)
addtag[i]+=p;
}
} int query(int l,int r,int p)
{
int ans=;
//左半散块
for(int i=l;i<=min(bl[l]*blo,r);i++)
if(val[i]+addtag[bl[l]]>=p) ans++;
if(bl[l]!=bl[r])// !
{//右半散块
for(int i=(bl[r]-)*blo+;i<=r;i++)
if(val[i]+addtag[bl[r]]>=p) ans++;
}
for(int i=bl[l]+;i<=bl[r]-;i++)//整块
{
int tmp=p-addtag[i];//求>=p,则先把加法标记减去
int pos=lower_bound(cnt[i].begin(),cnt[i].end(),tmp)-cnt[i].begin();
ans+=blo-pos;//注意这句 精髓
// ans+=find(i,tmp);
}
return ans;
} int main()
{
scanf("%d%d",&n,&Q);
for(int i=;i<=n;i++) scanf("%d",&val[i]);
blo=sqrt(n);
for(int i=;i<=n;i++)
{
bl[i]=(i-)/blo+;
cnt[bl[i]].push_back(val[i]);//记录每个块中元素
}
//对每个块中元素进行排序
for(int i=;i<=bl[n];i++)
sort(cnt[i].begin(),cnt[i].end());
while(Q--)
{
scanf("%s",opt+);
int x=,y=,z=;
scanf("%d%d%d",&x,&y,&z);
if(opt[]=='M')
add(x,y,z);
else if(opt[]=='A')
printf("%d\n",query(x,y,z));
}
return ;
}

贴心注释版

然鹅不吸氧会T掉一个点,可能是我lowerbound常数的锅锅?讨论里有人说要用longlong结果我用了longlong只会带来无端的CE/WA/RE。

Just be cautious.

bzoj3343 教主的魔法【分块入门】By cellur925的更多相关文章

  1. BZOJ3343: 教主的魔法 分块

    2016-05-28  10:27:19 题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3343 比较显然的分块题,分块后块内排序,维护整块的附 ...

  2. P2801 教主的魔法(分块入门)

    两个月之前听yyr学长讲的分块,感觉是个很神奇的暴力,但到现在还是懵的一匹 #include<bits/stdc++.h> using namespace std; ; int belon ...

  3. [bzoj3343]教主的魔法——分块

    Brief description 给定一个数列,您需要支持一下两种操作: 给[l,r]同加一个数 询问[l,r]中有多少数字大于或等于v Algorithm analyse 这个题一时想不到什么有效 ...

  4. BZOJ-3343教主的魔法+分块(大块排序二分)

    传送门:https://www.luogu.org/problemnew/show/P2801 参考:http://hzwer.com/2784.html  感觉思路无比清晰:) ps:我在洛谷A的, ...

  5. bzoj3343: 教主的魔法 分块 标记

    修改:两边暴力重构,中间打标记.复杂度:O(n0.5) 查询:中间二分两边暴力.O(n0.5logn0.5) 总时间复杂度O(n*n0.5logn0.5) 空间复杂度是n级别的 标记不用下传因为标记不 ...

  6. [BZOJ3343]教主的魔法

    [BZOJ3343]教主的魔法 试题描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.… ...

  7. Luogu 2801 教主的魔法 | 分块模板题

    Luogu 2801 教主的魔法 | 分块模板题 我犯的错误: 有一处l打成了1,还看不出来-- 缩小块大小De完bug后忘了把块大小改回去就提交--还以为自己一定能A了-- #include < ...

  8. BZOJ 3343: 教主的魔法(分块+二分查找)

    BZOJ 3343: 教主的魔法(分块+二分查找) 3343: 教主的魔法 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1172  Solved:  ...

  9. 【BZOJ-3343】教主的魔法 分块

    3343: 教主的魔法 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 950  Solved: 414[Submit][Status][Discuss ...

随机推荐

  1. Oracle db中禁止使用sqlplus的方法

    先记录下来: How to Disable a SQL*Plus Connection for a User (文档 ID 124121.1)

  2. mysql添加删除索引,查看某个表的建表语句

    查看某个表的建表语句 :show create table data_statdata; drop index ts on data_statdata; 索引是加速查询的主要手段,特别对于涉及多个表的 ...

  3. plsql 无需配置客户端连接.

    plsql 无需配置客户端连接. (DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.0.5)(PORT=1521)))(C ...

  4. CodeVS2492 上帝造题的七分钟2(树状数组+并查集)

    传送门 树状数组模板题.注意优化,假设某个数的值已经是1了的话.那么我们以后就不用对他进行操作了,这个能够用并查集实现. 这道题还有个坑的地方,给出查询区间端点的a,b,有可能a>b. #inc ...

  5. java中InputStream String

    Java 中获取输入流时,有时候须要将输入流转成String,以便获取当中的内容 ,以下总结一下 InputStream 转成String 的方式  方法1: public String conver ...

  6. 【特征检測】BRIEF特征点描写叙述算法

    简单介绍 BRIEF是2010年的一篇名为<BRIEF:Binary Robust Independent Elementary Features>的文章中提出,BRIEF是对已检測到的特 ...

  7. 修复Xcode升级错误 — PCH File Error

    http://www.rockia.net/2013/03/fix-xcode-update-pch-file-error Error:PCH File Built From A Different ...

  8. char* strcpy( char* dest, const char* src ), int binary_search(int *arr, int key, int n), 可能的实现

    #include <stdio.h> char* stringCopy( char* dest, const char* src ) { size_t i = 0; while (dest ...

  9. JVM垃圾回收算法 及 垃圾收集器

    摘自<深入理解Java虚拟机> 一.什么是: GC算法是 方法论,那么垃圾收集器就是具体的 实现. 二.四种 垃圾回收算法 1.标记-清除算法:最基础的收集算法:不足有两点:1标记和清除两 ...

  10. CentOS 7.2 安装Gerrit 2.14.6

    1.环境 本文使用VMWare虚拟机进行实验. 2核CPU,4GB内存,20GB硬盘,IP:192.168.159.131 CentOS 7.2最小安装(CentOS-7-x86_64-Minimal ...