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

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

这大概是本蒟蒻的第一题正式分块,思想是在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. ActiveMQ(二) 转

    package pfs.y2017.m11.mq.activemq.demo02; import java.util.concurrent.atomic.AtomicInteger; import j ...

  2. 理解OpenStack认证:Keystone PKI

    原文链接: https://www.mirantis.com/blog/understanding-openstack-authentication-keystone-pki/ The latest ...

  3. asp.net+access实现DropDownList与RadDatePicker同步筛选

    这里没有使用SqlServer是因为老师要求使用access. 前台代码 <table style="margin:auto"> <tr><td cl ...

  4. CH 5105 Cookies(贪心+DP)

    \(CH 5105 Cookies\) \(solution:\) 真是好题一道!这道题我想了很久很久,就得这一题可以直接完全贪心,可惜最后还是失败了,但是对贪心的深入思考也换来了一个最优解方案.然后 ...

  5. C# partial分部类和分部方法

    1.https://www.cnblogs.com/xcsn/p/7533238.html 它是一个关键字修饰符.可以将类或结构.接口或方法的定义拆分到两个或更多个源文件中. 每个源文件包含类型或方法 ...

  6. HDU 6109 数据分割 【并查集+set】 (2017"百度之星"程序设计大赛 - 初赛(A))

    数据分割 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  7. oracle:数据库版本问题导致的bug

    公司开发出来的系统,由于各现场oracle数据库版本有10.2.0.4.11.2.0.1.11.2.0.3.11.2.0.4: 进而会导致版本不一导致错误问题.下面列举2个: 1.wm_concat ...

  8. 修改fuse库成功

    使用的是fuse-2.9.2 在lib目录下的helper.c的fuse_main_real函数里打印一句话,然后将fuse库编译并install. 对ssfs进行编译,运行后,出现了打印的那句话! ...

  9. NSString -- UILabel中字体有多种颜色,字符串自动计算高度/换行

    一:UILabel中字体有多种颜色 UILabel *label = [[UILabel alloc] init]; label.frame = CGRectMake(, , , ); label.b ...

  10. [Java] static, final

    1.静态成员 静态成员独立于类的对象,先于对象的存在而存在.无论创建了类的多少个对象,静态成员都只有一个实例空间.一个静态变量被同一个类的所有对象共享.当改变了其中一个对象的静态变量时,其余对象的静态 ...