做法:考虑对函数进行分块(1-根号n,根号n+1-根号2*n,之类的函数)
我们可以通过差分预处理出每个块中的函数分别对应几个a[i]之和
即sigma(a[i]*k[i])中的系数k[i],然后预处理出每个块的和记为sum[i]
考虑修改操作,显然很简单我们可以直接改一下每个块的sum值
然后考虑查询操作,整块的随便做,但是零散的反而麻烦了
所以用树状数组记录一下a的前缀和就行了
唯一的坑点:long long好像不够,要开unsigned long long才行
代码:
#include<bits/stdc++.h> #define N 500005 #define lll unsigned long long using namespace std; lll ll[N],rr[N],a[N],c[N],l[N],r[N],cnt[405][N/5+5],sum[405]; lll n,Q,opt,x,y,block,num; inline lll gt(lll x){return (x-1)/block+1;} inline lll lowbit(lll x){return x&-x;} inline void add(lll x,lll y){for(lll i=x;i<=n;i+=lowbit(i))c[i]+=y;} inline lll gtsum(lll x){lll ans=0;for(lll i=x;i;i-=lowbit(i))ans+=c[i];return ans;} inline void change(lll x,lll y){ add(x,y-a[x]); for (lll i=1;i<=num;i++) sum[i]+=cnt[i][x]*(y-a[x]); a[x]=y; } inline lll query(lll x,lll y){ lll ans=0; if (gt(x)==gt(y)||gt(x)+1==gt(y)) for (lll i=x;i<=y&&i<=n;i++) ans+=gtsum(r[i])-gtsum(l[i]); else { for (lll i=gt(x)+1;i<gt(y);i++) ans+=sum[i]; for (lll i=x;i<=rr[gt(x)]&&i<=n;i++) ans+=gtsum(r[i])-gtsum(l[i]); for (lll i=ll[gt(y)];i<=y&&i<=n;i++) ans+=gtsum(r[i])-gtsum(l[i]); } return ans; } int main(){ scanf("%llu",&n);block=(lll)sqrt(n); for (lll i=1;i<=n;i++) scanf("%llu",&a[i]),add(i,a[i]); num=n/block;if (n%block) num++; for (lll i=1;i<=num;i++) ll[i]=(i-1)*block+1,rr[i]=i*block;rr[num]=n; for (lll i=1;i<=n;i++) scanf("%llu%llu",&l[i],&r[i]),l[i]--; for (lll i=1;i<=num;i++){ for (lll j=ll[i];j<=rr[i];j++){ cnt[i][l[j]+1]++; cnt[i][r[j]+1]--; } } for (lll i=1;i<=num;i++){ for (lll j=1;j<=n;j++){ cnt[i][j]+=cnt[i][j-1]; sum[i]=sum[i]+cnt[i][j]*a[j]; } } //printf("%d\n",cnt[2][4]); scanf("%llu",&Q); while (Q--){ scanf("%llu%llu%llu",&opt,&x,&y); if (opt==1) change(x,y); else printf("%llu\n",query(x,y)); } return 0; }