2018网络预选赛 徐州H 线段树+树状数组
设读入的数组是a,树状数组用来维护a数组区间和sum,线段树用来维护一个另一个数组ssum的区间和,区间每个点a[i]*(n-i+1),那么l-r的答案是l-r的ssum-(n-r)*(sum[r]-sum[l-1]) (纸上画一下就知道了)
#include<bits/stdc++.h> using namespace std; const int maxn=100010; int n,q,ql,qr,p; long long v,_sum; long long sum[maxn],ssum[4*maxn],addv[4*maxn],c[maxn]; long long ask(int x){ long long ans=0; for(;x;x-=x&-x)ans+=sum[x]; return ans; } int add(int x,int y){ for(;x<=n;x+=x&-x)sum[x]+=y; } void update(int o,int L,int R){ if(L==R){ ssum[o]=v*(n-L+1); return; } int M=L+(R-L)/2; if(p<=M)update(o*2,L,M); else update(o*2+1,M+1,R); ssum[o]=ssum[o*2]+ssum[o*2+1]; } long long query(int o,int L,int R){ int M=L+(R-L)/2; long long ans=0; if(ql<=L&&R<=qr)return ssum[o]; if(ql<=M)ans+=query(o*2,L,M); if(M<qr)ans+=query(o*2+1,M+1,R); return ans; } int main(){ int flag,a,b; scanf("%d%d",&n,&q); for(int i=1;i<=n;i++){ scanf("%lld",&c[i]); add(i,c[i]); } for(int i=n;i>=1;i--){ p=i; v=c[i]; update(1,1,n); } while(q--){ scanf("%d%d%d",&flag,&a,&b); if(flag==1){ ql=a,qr=b; _sum=query(1,1,n); printf("%lld\n",_sum-(n-b)*(ask(b)-ask(a-1))); } else{ add(a,b-c[a]); ql=a,qr=n; p=a,v=b; update(1,1,n); c[a]=b; } } }