们把每m个元素分为一块,共有n/m块
每次区间加的操作会涉及O(n/m)个整块
以及区间两侧两个不完整的块中至多2m个元素
我们给每个块设置一个加法标记
每次操作对每个整块直接O(1)标记
不完整的块由于元素比较少,暴力修改元素的值
每次询问时返回元素的值加上其所在块的加法标记
这样每次操作的复杂度是O(n/m)+O(m)
m取√n时总复杂度最低
LOJ6277
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=50005; 6 int n,blo; 7 int v[maxn],bl[maxn],atag[maxn]; 8 inline long long read() 9 { 10 long long x=0,f=1;char ch=getchar(); 11 while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 13 return x*f; 14 } 15 void add(int a,int b,int c) 16 { 17 for(int i=a;i<=min(bl[a]*blo,b);i++) v[i]+=c; 18 if(bl[a]!=bl[b]) 19 for(int i=(bl[b]-1)*blo+1;i<=b;i++) v[i]+=c; 20 for(int i=bl[a]+1;i<=bl[b]-1;i++) atag[i]+=c; 21 } 22 int main() 23 { 24 n=read();blo=sqrt(n); 25 for(int i=1;i<=n;i++) v[i]=read(); 26 for(int i=1;i<=n;i++) bl[i]=(i-1)/blo+1; 27 for(int i=1;i<=n;i++) 28 { 29 int f=read(),a=read(),b=read(),c=read(); 30 if(f==0) add(a,b,c); 31 if(f==1) printf("%d ",v[b]+atag[bl[b]]); 32 } 33 return 0; 34 }