分块 学习笔记
前言
忽然发现分块大法很好用,然而本蒟蒻不会…所以心血来潮学习了分块
例题
Link
Code
代码语言:javascript复制#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
using namespace std;
#define re register
#define It std::set<int>::iterator
#define int long long
struct FastIO{
static const int S=1048576;
char buf[S],*L,*R;int stk[20],Top;
~FastIO(){clear();}
inline char nc(){return L==R&&(R=(L=buf) fread(buf,1,S,stdin),L==R)?EOF:*L ;}
inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
inline void pc(char ch){Top==S&&(clear(),0);buf[Top ]=ch;}
inline void endl(){pc('n');}
FastIO& operator >> (int& ret){
ret=0;int f=1;char ch=nc();
while(ch<'0'ch>'9'){if(ch=='-')f=-f;ch=nc();}
while(ch>='0'&&ch<='9'){ret=ret*10 ch-'0';ch=nc();}
ret*=f;return *this;
}
FastIO& operator >> (char* s){
re int Len=0;re char ch=nc();
while(ch!='n'){
*(s Len)=ch;
Len ;
ch=nc();
}
}
FastIO& operator << (int x){
if(x<0){pc('-');x=-x;}
do{stk[ stk[0]]=x;x/=10;}while(x);
while(stk[0]) pc('0' stk[stk[0]--]);
return *this;
}
FastIO& operator << (char ch){pc(ch);return *this;}
FastIO& operator << (string str){
re int Len=str.size()-1;for(stk[0]=0;Len>=0;Len--) stk[ stk[0]]=str[Len];
while(stk[0]) pc(stk[stk[0]--]);
return *this;
}
}fin,fout;
int n,m,ans,a[100010],lef[100010],rig[100010],id[100010],sum[100010],add[100010],tot,sz;
#define File freopen("1.in","r",stdin);freopen("1.out","w",stdout);
inline void Print(){
for(int i=1;i<=tot;i ){
cout<<i<<":"<<lef[i]<<" "<<rig[i]<<" "<<add[i]<<" "<<sum[i]<<endl;
}
}
signed main(){
fin>>n>>m;
for(int i=1;i<=n;i ) fin>>a[i];
sz=sqrt(n);tot=sz;//每个块大小为sqrt(n)
if(sz*sz<=n) tot;//还有多余
for(int i=1;i<=n;i ){
id[i]=(i/sz) (i%sz==0?0:1);//每个数所属的块的编号
sum[id[i]] =a[i];//每个块内的和
if(id[i]==tot) lef[i]=sz*sz,rig[i]=n;//确定最后一个块的左右端点
lef[id[i]]=id[i]*sz-sz 1;rig[id[i]]=id[i]*sz;//确定这个块的左右端点
}
for(int op,l,r,v,i=1;i<=m;i ){
fin>>op>>l>>r;
if(op==1){
fin>>v;
for(int i=l;i<=min(r,rig[id[l]]);i ) a[i] =v,sum[id[i]] =v;//把左边的暴力加入
for(int i=max(l,lef[id[r]]);i<=r;i ) a[i] =v,sum[id[i]] =v;//把右边的暴力加入
for(int i=id[l] 1;i<=id[r]-1;i ) add[i] =v;//把中间的加入
if(id[l]==id[r]) for(int i=l;i<=r;i ) a[i]-=v;//注意当l,r在同一个块内情况
}else{
ans=0;
for(int i=l;i<=min(r,rig[id[l]]);i ) ans =a[i] add[id[i]];//同上
for(int i=max(l,lef[id[r]]);i<=r;i ) ans =a[i] add[id[i]];//同上
for(int i=id[l] 1;i<=id[r]-1;i ) ans =sum[i] add[i]*(rig[i]-lef[i] 1);//同上
if(id[l]==id[r]) ans-=a[l] a[r] add[id[l]] add[id[r]];//注意当l,r在同一个块内情况
fout<<ans<<"n";
}
}
}