之前用线段树做的,后来试了一下发现这道题可以用分块通过,请问分块的时间复杂度是 O(mn) 吗,属于正解吗?
代码如下:
#include<bits/stdc++.h>
template<typename T> T max(T a, T b){return (a>b)?a:b;}
template<typename T> T min(T a, T b){return (a<b)?a:b;}
template<typename T> T gcd(T a, T b){while(b^=a^=b^=a%=b); return a;}
const char endl='\n';
const int inf=0x3f3f3f3f;
const int MAXN=100000+5;
const int SQ=500+5;
long long st[SQ], ed[SQ], size[SQ], bel[MAXN];
long long arr[MAXN], sum[SQ], mark[SQ];
void init(long long n)
{
long long block=sqrt(n);
for(long long i=1;i<=block;i++)
{
st[i]=n/block*(i-1)+1;
ed[i]=n/block*i;
}
ed[block]=n;
for(long long i=1;i<=block;i++)
for(long long j=st[i];j<=ed[i];j++)
bel[j]=i;
for(long long i=1;i<=block;i++)
size[i]=ed[i]-st[i]+1;
}
void update_section(long long l, long long r, long long v)
{
if(bel[l]==bel[r])
{
for(long long i=l;i<=r;i++)
{
arr[i]+=v;
sum[bel[i]]+=v;
}
}
else
{
for(long long i=l;i<=ed[bel[l]];i++)
{
arr[i]+=v;
sum[bel[i]]+=v;
}
for(long long i=st[bel[r]];i<=r;i++)
{
arr[i]+=v;
sum[bel[i]]+=v;
}
for(long long i=bel[l]+1;i<bel[r];i++)
mark[i]+=v;
}
}
long long search_section(long long l, long long r)
{
long long s=0;
if(bel[l]==bel[r])
{
for(long long i=l;i<=r;i++)
s+=arr[i]+mark[bel[i]];
}
else
{
for(long long i=l;i<=ed[bel[l]];i++)
s+=arr[i]+mark[bel[i]];
for(long long i=st[bel[r]];i<=r;i++)
s+=arr[i]+mark[bel[i]];
for(long long i=bel[l]+1;i<bel[r];i++)
s+=sum[i]+mark[i]*size[i];
}
return s;
}
int main()
{
long long n, m;
scanf("%lld%lld", &n, &m);
for(long long i=1;i<=n;i++)
scanf("%lld", &arr[i]);
init(n);
long long block=sqrt(n);
for(long long i=1;i<=block;i++)
for(long long j=st[i];j<=ed[i];j++)
sum[i]+=arr[j];
while(m--)
{
long long op;
scanf("%lld", &op);
if(op==1)
{
long long l, r, v;
scanf("%lld%lld%lld", &l, &r, &v);
update_section(l, r, v);
}
else if(op==2)
{
long long l, r;
scanf("%lld%lld", &l, &r);
printf("%lld\n", search_section(l, r));
}
}
return 0;
}