分块
分块
瞎搞个玩意支持对一个数组区间求和,单点修改。
啊,已经有很多方法了?
- 朴素算法:O(1)修改,O(n)查询
- 前缀和:O(n)修改,O(1)查询
- 树状数组:O(logn)修改,O(logn)查询
看似好像齐全了……然而还是有个比朴素好的东西:分块
我们把整个数组分成sqrt(n)个部分,每个部分维护区间和和元素值。
操作:
(1)修改:直接修改:O(1)
(2)查询:对于中间的部分,直接将区间和加起来,两边零碎的朴素求法,O(sqrt(n))
啊,有了树状数组,要你何用?
好像有玄学做法……亦或者你的查询多呢,蛤蛤。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
using namespace std;
const int maxn=100000+1000;
const double eps=0.000001;
int n,m,M,len,k,x,y,a[maxn],s[maxn];
void init() //初始化
{
M=(int)(sqrt(n)+eps);
if (n%M==0) len=n/M; else len=n/M+1;
rep(i,0,M-1)
rep(j,i*len,(i+1)*len-1) s[i]+=a[j];
}
void update(int x,int k) //修改
{
a[x]+=k;s[x/len]+=k;
}
int query(int x,int y) //查询
{
int ans=0;
if ((x/len)==(y/len))
while (x<=y) ans+=a[x++]; //在一个区间里,直接加
else
{
while ((x%len)>0) ans+=a[x++]; //算左边零碎的
while (((y+1)%len)>0) ans+=a[y--]; //算右边零碎的
while (x<y) {ans+=s[x/len];x+=len;} //算中间整的
}
return ans;
}
int main()
{
scanf("%d",&n);
rep(i,0,n-1) scanf("%d",&a[i]);
init();
scanf("%d",&m);
rep(i,1,m)
{
scanf("%d%d%d",&k,&x,&y);
if (k==1) update(x-1,y); else printf("%d\n",query(x-1,y-1));
}
return 0;
}
区间修改:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
using namespace std;
const int MAXN=200000+23;
const int EPS=1e-6;
typedef long long LL;
int B,n,m,k,l,r,x,a[MAXN],num[MAXN];
LL S[MAXN],Tag[MAXN];
void add(int l,int r,int v)
{
rep(i,l,min(num[l]*B,r))
a[i]+=v,S[num[i]]+=v;
if (num[l]!=num[r])
rep(i,num[r]*B-B+1,r)
a[i]+=v,S[num[i]]+=v;
rep(i,num[l]+1,num[r]-1)
Tag[i]+=v;
}
LL query(int l,int r)
{
LL ans=0;
rep(i,l,min(num[l]*B,r)) ans+=a[i]+Tag[num[l]];
if (num[l]!=num[r])
rep(i,num[r]*B-B+1,r) ans+=a[i]+Tag[num[r]];
rep(i,num[l]+1,num[r]-1)
ans+=S[i]+B*Tag[i];
return ans;
}
int main()
{
scanf("%d",&n);
B=(int)(sqrt(n)+EPS);
memset(S,0,sizeof(S));
rep(i,1,n)
{
scanf("%d",&a[i]);
num[i]=(i-1)/B+1;
S[num[i]]+=a[i];
}
scanf("%d",&m);
rep(i,1,m)
{
scanf("%d",&k);
if (k==1)
{
scanf("%d%d%d",&l,&r,&x);
add(l,r,x);
}
else
{
scanf("%d%d",&l,&r);
printf("%lld\n",query(l,r));
}
}
return 0;
}

浙公网安备 33010602011771号