是个论文题
题目大意,给定n个数字和n个区间,每次修改一个数字的权值或者询问一段区间的区间的和。
考虑分块,记录ans[i]表示询问第i块的答案,con[i][j]表示第i块的若干区间有多少包含位置j,那么每次A[x]加上y就会使得ans[i]+=con[i][x]*y
考虑询问零散的块怎么办,就是一个单点修改区间求和,直接做带log,考虑修改只有q次,但是询问有nsqrt(q)次,因此维护用分块维护前缀和即可,这样就只有根号了。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define ull unsigned long long
#define N 100010
#define BC 500
#define gc getchar()
using namespace std;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct black_box_of_data_structer{
int sz,bc,n,L[BC],R[BC],bel[N];ull tag[BC],val[N];
inline int init(int *a,int _n)
{
n=_n,sz=sqrt(n+0.5),bc=(n-1)/sz+1;
for(int i=1;i<=bc;i++)
{
L[i]=(i-1)*sz+1,R[i]=min(i*sz,n),tag[i]=0;
for(int j=L[i];j<=R[i];j++) val[j]=val[j-1]+a[j],bel[j]=i;
}
return 0;
}
inline int update(int p,int v)
{
for(int i=bel[p]+1;i<=bc;i++) tag[i]+=v;
for(int i=p;i<=R[bel[p]];i++) val[i]+=v;
return 0;
}
inline ull query(int p) { return val[p]+tag[bel[p]]; }
inline ull query(int l,int r) { return query(r)-query(l-1); }
}ds;
int l[N],r[N],a[N],bel[N],L[BC],R[BC],con[BC][N];ull ans[BC];
int main()
{
int n=inn();
for(int i=1;i<=n;i++) a[i]=inn();ds.init(a,n);
for(int i=1;i<=n;i++) l[i]=inn(),r[i]=inn();
int sz=sqrt(n+0.5),bc=(n-1)/sz+1;
for(int i=1;i<=bc;i++)
{
L[i]=(i-1)*sz+1,R[i]=min(i*sz,n);
for(int j=L[i];j<=R[i];j++)
bel[j]=i,ans[i]+=ds.query(l[j],r[j]),
con[i][l[j]]++,con[i][r[j]+1]--;
for(int j=1;j<=n;j++) con[i][j]+=con[i][j-1];
}
int q;scanf("%d",&q);
while(q--)
if(inn()==1)
{
int x=inn(),y=inn(),z=y;
z=y-a[x],a[x]=y,y=z,ds.update(x,y);
for(int i=1;i<=bc;i++) ans[i]+=(ull)con[i][x]*y;
}
else{
int x=inn(),y=inn(),bx=bel[x],by=bel[y];ull Ans=0;
if(bx==by) for(int i=x;i<=y;i++) Ans+=ds.query(l[i],r[i]);
else{
for(int i=bx+1;i<by;i++) Ans+=ans[i];
for(int i=x;i<=R[bx];i++) Ans+=ds.query(l[i],r[i]);
for(int i=L[by];i<=y;i++) Ans+=ds.query(l[i],r[i]);
}
printf("%llu\n",Ans);
}
return 0;
}