题意:
单点修改$a$
询问$a$的区间和$f$的区间和
原来普通计算机是这道题改编的吧...
对$f$分块,预处理$c[i][j]$为块i中$a_j$出现几次,$O(NH(N))$,只要每个块差分加上然后扫一遍就行了不用树状数组之类的
修改,整块直接改,还要单点修改$a$
查询,整块直接查,两边暴力查询$a$的区间和
对$a$的操作可以用树状数组,也可以再分块维护前缀和实现$O(N)-O(1)$
这样不用带一个log总复杂度$O(NH(N))$
实测快了0.4s
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int N=1e5+5,M=350; typedef unsigned long long ll; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,Q,op,x,y; ll a[N],s[N]; int pos[N],m,block; struct _Block{int l,r;} b[M], f[N]; inline void iniBlock(){ block=sqrt(n); m=(n-1)/block+1; for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1; for(int i=1;i<=m;i++) b[i].l=(i-1)*block+1,b[i].r=i*block; b[m].r=n; } struct BlockA{ ll add[M]; void Add(int x,ll v){ for(int i=x;i<=b[pos[x]].r;i++) s[i]+=v; for(int i=pos[x]+1;i<=m;i++) add[i]+=v; } ll fun(_Block &x){ return s[x.r]+add[ pos[x.r] ] - (s[x.l-1]+add[ pos[x.l-1] ]); } }A; struct Block{ int c[M][N],s[N]; ll sum[N]; void ini(){ for(int i=1;i<=m;i++){ for(int j=b[i].l ; j<=b[i].r ; j++) s[ f[j].l ]++,s[ f[j].r+1 ]--; int *cc=c[i]; for(int j=1;j<=n;j++) cc[j]=cc[j-1]+s[j],sum[i]+=cc[j]*a[j],s[j]=0; } } void cha(int x,ll v){ ll t=v-a[x]; A.Add(x,t); for(int i=1;i<=m;i++) sum[i]+=c[i][x]*t; a[x]=v; } ll que(int l,int r){ ll re=0; if(pos[l]==pos[r]) for(int i=l;i<=r;i++) re+=A.fun(f[i]); else{ for(int i=pos[l]+1;i<=pos[r]-1;i++) re+=sum[i]; for(int i=l;i<=b[pos[l]].r;i++) re+=A.fun(f[i]); for(int i=b[pos[r]].l;i<=r;i++) re+=A.fun(f[i]); } return re; } }B; int main(){ freopen("in","r",stdin); n=read(); for(int i=1;i<=n;i++) a[i]=read(),s[i]=s[i-1]+a[i]; for(int i=1;i<=n;i++) f[i].l=read(),f[i].r=read(); iniBlock();B.ini(); Q=read(); while(Q--){ op=read();x=read();y=read(); if(op==1) B.cha(x,y); else printf("%llu ",B.que(x,y)); } }
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; #define pii pair<int,int> #define MP make_pair #define fir first #define sec second const int N=1e5+5,M=350; typedef unsigned long long ll; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,Q,op,x,y; ll a[N]; pii f[N]; struct BIT{ ll c[N]; inline void add(int p,ll v){for(;p<=n;p+=(p&-p)) c[p]+=v;} inline ll sum(int p){ll re=0;for(;p;p-=(p&-p)) re+=c[p];return re;} }C; inline ll fun(int x){return C.sum(f[x].sec)-C.sum(f[x].fir-1);} struct _Block{int l,r;ll sum;}; struct Block{ int block,m,pos[N],c[M][N],s[N]; _Block b[M]; void ini(){ block=sqrt(n); m=(n-1)/block+1; for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1; for(int i=1;i<=m;i++){ b[i].l=(i-1)*block+1; b[i].r= i==m ? n : i*block; for(int j=b[i].l ; j<=b[i].r ; j++) s[ f[j].fir ]++,s[ f[j].sec+1 ]--; int *cc=c[i]; for(int j=1;j<=n;j++) cc[j]=cc[j-1]+s[j],b[i].sum+=cc[j]*a[j],s[j]=0; } } void cha(int x,ll v){ v-=a[x]; for(int i=1;i<=m;i++) b[i].sum+=c[i][x]*v; C.add(x,v); a[x]+=v; } ll que(int l,int r){ ll re=0; if(pos[l]==pos[r]) for(int i=l;i<=r;i++) re+=fun(i); else{ for(int i=pos[l]+1;i<=pos[r]-1;i++) re+=b[i].sum; for(int i=l;i<=b[pos[l]].r;i++) re+=fun(i); for(int i=b[pos[r]].l;i<=r;i++) re+=fun(i); } return re; } }B; int main(){ freopen("in","r",stdin); n=read(); for(int i=1;i<=n;i++) a[i]=read(),C.add(i,a[i]); for(int i=1;i<=n;i++) f[i].fir=read(),f[i].sec=read(); B.ini(); Q=read(); while(Q--){ op=read();x=read();y=read(); if(op==1) B.cha(x,y); else printf("%llu ",B.que(x,y)); } }