【BZOJ】3343 教主的魔法 分块

来源:互联网 发布:excel如何导入外部数据 编辑:程序博客网 时间:2024/04/30 08:24

题目传送门

分块什么的最好了~(至少简单易懂,代码还比较好写)

这题就当是我学习了分块的flag吧。

其实分块就是把原来n个元素分成sqrt(n)块,每块有sqrt(n)个元素。

对于一段连续的区间修改,我们可以把这个区间分成若干个完整的块和两端剩下的元素。

对于完整的块,我们可以用和线段树一样的思想——延迟标记来记录当前块内所有元素的共同修改量;

对于两端剩下的元素,我们可以暴力修改。(暴力大法好~)

对于询问,我们可以再开一个数组,和之前的数组一样分块,但是要把每个块内的元素排序。

然后我们把询问拆分成若干个完整的块和两端剩下的元素。

对于完整的块,我们可以二分出块内的答案;对于两端剩下的元素,依然是暴力……

综上,这道题就被分块水过去了。(因为询问的次数比较小嘛)

附上AC代码:

#include <cstdio>#include <cctype>#include <cmath>#include <algorithm>#define N 1010using namespace std;int n,m,size,num,a[N*N],l[N],r[N],b[N*N],x,y,w,sy[N*N],lz[N];char c;inline char nc(){static char ch[100010],*p1=ch,*p2=ch;return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;}inline void read(int &a){static char c=nc();int f=1;for (;!isdigit(c);c=nc()) if (c=='-') f=-1;for (a=0;isdigit(c);a=a*10+c-'0',c=nc());a*=f;return;}inline void rebuild(int x){for (int i=l[x]; i<=r[x]; ++i) b[i]=a[i];return sort(b+l[x],b+r[x]+1);}inline void change(int x,int y,int w){if (sy[x]==sy[y]){for (int i=x; i<=y; ++i) a[i]+=w;return rebuild(sy[x]);}for (int i=sy[x]+1; i<=sy[y]-1; ++i) lz[i]+=w;for (int i=x; i<=r[sy[x]]; ++i) a[i]+=w;rebuild(sy[x]);for (int i=l[sy[y]]; i<=y; ++i) a[i]+=w;rebuild(sy[y]);return;}inline int find(int x,int y,int w){int l=x,r=y,ans=y+1,mid;while (l<=r){mid=(l+r)>>1;if (b[mid]<w) l=mid+1;else ans=mid,r=mid-1;}return y-ans+1;}inline int query(int x,int y,int w){int ans=0;if (sy[x]==sy[y]){for (int i=x; i<=y; ++i) if (a[i]>=w) ++ans;return ans;}for (int i=sy[x]+1; i<=sy[y]-1; ++i) ans+=find(l[i],r[i],w-lz[i]);for (int i=x; i<=r[sy[x]]; ++i) if (a[i]>=w) ++ans;for (int i=l[sy[y]]; i<=y; ++i) if (a[i]>=w) ++ans;return ans;}int main(void){read(num),read(m),size=sqrt(num),n=(num-1)/size+1; for (int i=1; i<=num; ++i){read(a[i]),b[i]=a[i],sy[i]=(i-1)/size+1;if (i%size==1) l[sy[i]]=i;if (i%size==0) r[sy[i]]=i;}if (!r[n]) r[n]=num;for (int i=1; i<=n; ++i) sort(b+l[i],b+r[i]+1);while (m--){c=nc();while (c!='M'&&c!='A') c=nc();read(x),read(y),read(w);switch (c){case 'M': change(x,y,w); break;case 'A': printf("%d\n",query(x,y,w)); break;}}return 0;}