传送门
题解:有种区间操作叫做线段树LAZY操作,但是还有种树状数组关于区间的操作很巧妙,使用两个树状数组进行维护。
第一种维护方法:
附上代码:
#include
#include
using namespace std;
typedef long long ll;
const int MAX_N=1e5+50;
const int MAX_Q=1e5+50;
int N,Q;
int A[MAX_N];
char T[MAX_Q];
int L[MAX_Q],R[MAX_Q],X[MAX_Q];
ll bit0[MAX_N],bit1[MAX_N];
ll sum(ll *b,int i)
{
ll s=0;
while(i>0){
s+=b[i];
i-=i&-i;
}
return s;
}
void add(ll *b,int i,int v)
{
while(i<=N){
b[i]+=v;
i+=i&-i;
}
}
void solve()
{
for(int i=1;i<=N;i++){
add(bit0,i,A[i]);
}
for(int i=1;i<=Q;i++){
if(T[i]=='C'){
add(bit0,L[i],-X[i]*(L[i]-1));
add(bit1,L[i],X[i]);
add(bit0,R[i]+1,X[i]*R[i]);
add(bit1,R[i]+1,-X[i]);
}else{
ll res=0;
res+=sum(bit0,R[i])+sum(bit1,R[i])*R[i];
res-=sum(bit0,L[i]-1)+sum(bit1,L[i]-1)*(L[i]-1);
printf("%lld\n",res);
}
}
}
int main()
{
scanf("%d%d",&N,&Q);
for(int i=1;i<=N;i++){
scanf("%d",&A[i]);
}
for(int i=1;i<=Q;i++){
getchar();
scanf("%c",&T[i]);
if(T[i]=='C'){
scanf("%d%d%d",&L[i],&R[i],&X[i]);
}else{
scanf("%d%d",&L[i],&R[i]);
}
}
solve();
return 0;
}
第二种维护方法:
#include
#include
using namespace std;
typedef long long ll;
const int maxn=1e5+50;
ll a[maxn],c1[maxn],c2[maxn],n,m,val,x,y;
char temp;
inline ll lowbit(ll x){
return x&-x;
}
void update(ll *q,ll x,ll val)
{
while(x<=n)
{
q[x]+=val;
x+=lowbit(x);
}
}
ll getsum(ll *q,ll x)
{
ll ans=0;
while(x)
{
ans+=q[x];
x-=lowbit(x);
}
return ans;
}
ll sum(ll x)
{
ll ans1,ans2;
ans1=x*getsum(c1,x);
ans2=getsum(c2,x);
return ans1-ans2;
}
ll inquire(ll x,ll y)
{
ll ans1,ans2;
ans1=sum(y);
ans2=sum(x-1);
return ans1-ans2;
}
int main() {
scanf("%lld%lld",&n,&m);
for(ll i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
update(c1,i,a[i]-a[i-1]);
update(c2,i,(i-1)*(a[i]-a[i-1]));
}
for(ll i=1; i<=m; i++)
{
getchar();
scanf("%c",&temp);
if(temp=='C')
{
scanf("%lld%lld%lld",&x,&y,&val);
update(c1,x,val);
update(c1,y+1,-val);
update(c2,x,(x-1)*val);
update(c2,y+1,-y*val);
}
else
{
scanf("%lld%lld",&x,&y);
printf("%lld\n",inquire(x,y));
}
}
}