题目描述
有一个长度为
n
的数组
n,q≤105,ai≤109
题解
分块。
设
si
为第
i
块的所有区间的区间和,
修改时修改树状数组和每个区间的区间和。设当前 ax=v ,则 si+=(y−v)×di,x
查询时完整的区间直接查询区间和,不完整的区间就暴力查询。
设块大小为
m
,时间复杂度为
当 m=nlogn−−−√ 时
T(n)min=O(nnlogn−−−−−√)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
ull c[100010];
int a[100010];
int n;
void add(int x,ull v)
{
for(;x<=n;x+=x&-x)
c[x]+=v;
}
ull sum(int x)
{
ull s=0;
for(;x;x-=x&-x)
s+=c[x];
return s;
}
int bl;
ull s[1010];
int d[1010][100010];
int l[100010];
int r[100010];
int block[100010];
int left[100010];
int right[100010];
int main()
{
memset(c,0,sizeof c);
// freopen("xsy2111.in","r",stdin);
// freopen("xsy2111.out","w",stdout);
int m;
scanf("%d",&n);
int i;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
add(i,a[i]);
}
bl=100;
m=(n+bl-1)/bl;
for(i=1;i<=n;i++)
block[i]=(i+bl-1)/bl;
for(i=1;i<=m;i++)
{
left[i]=(i-1)*bl+1;
right[i]=min(i*bl,n);
}
for(i=1;i<=n;i++)
{
scanf("%d%d",&l[i],&r[i]);
s[block[i]]+=sum(r[i])-sum(l[i]-1);
d[block[i]][l[i]]++;
if(r[i]<n)
d[block[i]][r[i]+1]--;
}
int j;
for(i=1;i<=m;i++)
for(j=2;j<=n;j++)
d[i][j]+=d[i][j-1];
int q;
scanf("%d",&q);
int op,x,y,k;
for(i=1;i<=q;i++)
{
scanf("%d%d%d",&op,&x,&y);
if(op==1)
{
int v=a[x];
for(j=1;j<=m;j++)
s[j]+=ull(y-v)*d[j][x];
add(x,y-v);
a[x]=y;
}
else
{
ull ans=0;
for(j=block[x];j<=block[y];j++)
if(left[j]>=x&&right[j]<=y)
ans+=s[j];
else
{
int mi=max(left[j],x);
int mx=min(right[j],y);
for(k=mi;k<=mx;k++)
ans+=sum(r[k])-sum(l[k]-1);
}
printf("%llu\n",ans);
}
}
return 0;
}