前言分块其实不是个数据结构而是个思想。综上大雾)让我们来到数列分块入门。正文首先我们需要阐述这个思想。题目传送门分块顾名思义就是将一个东西分成许多块。而数列分块则是将数列分成许多块我们设每块为B。比如区间加就是将在整块区间中直接加编号多余的直接暴力枚举。时间复杂度n/B2B而如何把复杂度降到最小呢这里用一个好推的东西:基本不等式然后带进去可得最小值为这里不用这么麻烦直接B即可。然后根据思路我们就知道怎么写了。Code#includebits/stdc.h #define int long long #define N 300005 using namespace std; int n,tag[N],a[N],B,tot; int id(int x){return (x-1)/B1;} int left(int id){return (id-1)*B1;} int right(int id){return min(n,id*B);} signed main(){ cinn; for(int i1;in;i)cina[i]; Bsqrt(n); totid(n); for(int i1;in;i){ int op,l,r,c; cinoplrc; if(!op){ int lbid(l),rbid(r); for(int ilb1;irb;i)tag[i]c; int lrright(lb),rlleft(rb); for(int il;ilr;i) if(ilir)a[i]c; if(lb!rb) for(int irl;ir;i) if(ilir)a[i]c; }else{ int idxid(r); couta[r]tag[idx]\n; } } }————————————小清新分割线————————————然后看这道题的promax P13979 数列分块入门 4其实大体思路相同只是这个mod需要处理一下。我们可以提前处理sum数组为块的总和。查询时整块sum散块加a和tag就好了。#includebits/stdc.h #define int long long #define N 300005 using namespace std; int n,tag[N],a[N],B,tot,sum[N]; int id(int x){return (x-1)/B1;} int left(int id){return (id-1)*B1;} int right(int id){return min(n,id*B);} signed main(){ cinn; for(int i1;in;i)cina[i]; Bsqrt(n); totid(n); for(int i1;itot;i){ int lleft(i),rright(i); sum[l]0; for(int jl;jr;j)sum[i]a[j]; tag[i]0; } for(int i1;in;i){ int op,l,r,c; cinoplrc; if(!op){ int lbid(l),rbid(r); for(int ilb1;irb;i)tag[i]c,sum[i]c*(right(i)-left(i)1); int llleft(lb),lrright(lb),rlleft(rb),rrright(rb); for(int ill;ilr;i) if(ilir)a[i]c,sum[lb]c; if(lb!rb) for(int irl;irr;i) if(ilir)a[i]c,sum[rb]c; }else{ int modc1,ans0; int lbid(l),rbid(r); int llleft(lb),lrright(lb),rlleft(rb),rrright(rb); for(int ilb1;irb;i)ansanssum[i]; for(int ill;ilr;i) if(ilir)ansansa[i]tag[lb]; if(lb!rb) for(int irl;irr;i) if(ilir)ansansa[i]tag[rb]; cout(ans%modmod)%modendl; } } }接下来是衍生。这是P13977 数列分块入门 2signed main(){ cinn; for(int i1;in;i)cina[i].v,a[i].ii; Bsqrt(n); totid(n); for(int i1;itot;i){ int blleft(i),brright(i); for(int jbl;jbr;j)b[j]a[j].v; sort(bbl,bbr1); } for(int i1;in;i){ int op,l,r,c; cinoplrc; int lbid(l),rbid(r); int lrright(lb),rlleft(rb); int rrright(rb),llleft(lb); if(!op){ for(int ilb1;irb;i)tag[i]c; for(int ill;ilr;i){ if(a[i].ila[i].ir)a[i].vc; b[i]a[i].v; } sort(bll,blr1); if(lb!rb){ for(int irl;irr;i){ if(a[i].ila[i].ir)a[i].vc; b[i]a[i].v; } sort(brl,brr1); } }else{ int xc*c,cnt0; for(int ilb1;irb;i){ int blleft(i),brright(i); cntlower_bound(bbl,bbr1,x-tag[i])-b-bl; } for(int il;imin(r,lr);i) if(a[i].vtag[lb]x)cnt; if(lb!rb){ for(int irl;ir;i) if(a[i].vtag[rb]x)cnt; } coutcnt\n; } } }刚开始处理一下查询时这边x^2的可以直接lower_bound剩下的就差不多了。这是P13978 数列分块入门 3signed main(){ cinn; for(int i1;in;i)cina[i].v,a[i].ii; Bsqrt(n); totid(n); for(int i1;itot;i){ int blleft(i),brright(i); for(int jbl;jbr;j)b[j]a[j].v; sort(bbl,bbr1); } for(int i1;in;i){ int op,l,r,c; cinoplrc; int lbid(l),rbid(r); int lrright(lb),rlleft(rb); int rrright(rb),llleft(lb); if(!op){ for(int ilb1;irb;i)tag[i]c; for(int ill;ilr;i){ if(a[i].ila[i].ir)a[i].vc; b[i]a[i].v; } sort(bll,blr1); if(lb!rb){ for(int irl;irr;i){ if(a[i].ila[i].ir)a[i].vc; b[i]a[i].v; } sort(brl,brr1); } }else{ int xc,ans-0x3f3f3f3f3f3f3f3f; for(int ilb1;irb;i){ int blleft(i),brright(i); int tmpx-tag[i]; auto itlower_bound(bbl,bbr1,tmp); if(it!bbl)ansmax(ans,*(it-1)tag[i]); } for(int ill;ilr;i){ if(a[i].ila[i].ir){ int cura[i].vtag[lb]; if(curx)ansmax(ans,cur); } } if(lb!rb){ for(int irl;irr;i){ if(a[i].ila[i].ir){ int cura[i].vtag[rb]; if(curx)ansmax(ans,cur); } } } if(ans-0x3f3f3f3f3f3f3f3f)cout-1\n; else coutans\n; } } }这里只是查询改一下。主要是规整区域用lower_bound去计算max边角料直接暴力求就好了。后记