一个简单的整数问题2
题意:给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:
1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。
2、“Q l r”,表示询问 数列中第 l~r 个数的和。
对于每个询问,输出一个整数表示答案。
思路:用树状数组进行区间操作。用一个数组b[i]代表当操作为[l,r]同时d操作时则b[r+1]-d,b[l]+d。这样求的前后缀未变。树状数组维护b前缀,相当于只有b[l,r]变了,
然后再用个树状数组维护i*b[i]的前缀。所以求区间[l,r]的和等于(sum[r]+(r+1)*ask(b,r)-ask(c,r))-(sum[l-1]+(l-1+1)*ask(b,l-1)-ask(c,l-1))。如何维护详见代码。
#include<cstring> #include<algorithm> #include<vector> #include<map> #include<queue> #include<cstdio> #include<cmath> #define ll long long #define lowbit(x) x&(-x) using namespace std; const int N=2e5+10; ll a[N],c[2][N],n,m,sum[N]; ll ask(int t,ll x) { ll ans=0; for(;x;x-=lowbit(x)) ans+=c[t][x]; return ans; } void add(int t,ll x,ll y) { for(;x<=n;x+=lowbit(x)) c[t][x]+=y; } int main() { scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); sum[i]=sum[i-1]+a[i]; } while(m--) { ll l,r; ll t; ll ans; char s[2]; scanf("%s",s); if(s[0]=='Q') { scanf("%lld%lld",&l,&r); ans=sum[r]+(r+1)*ask(0,r)-ask(1,r); ans-=sum[l-1]+l*ask(0,l-1)-ask(1,l-1); printf("%lld\n",ans); } else { scanf("%lld%lld%lld",&l,&r,&t); add(0,l,t); add(0,r+1,-t); add(1,l,l*t); add(1,r+1,-(r+1)*t); } } }