ps:博主又A这种水题显然是为了水blog有新姿势。
题目梗概
区间加,询问区间和。
解题思路
什么垃圾,直接线段树。
树状数组也可以区间加的啊,代码短小,常数小。
当然与普通树状数组有所不同。
设
a[i]=w[i]−w[i−1]
,这样修改区间
[L,R]
显然只需要修改
a[L],a[R+1]
,
[1,x]
的和显然就是
∑i=11a[i]+∑i=12a[i]+...+∑i=1xa[i]
稍微化一下就是
n∗∑i=1xa[i]−(0∗a[1]+1∗a[2]+...+(x−1)∗a[x])
那么我们在维护 a[i] 的同时也维护一个 b[i]=(i−1)∗a[i] 。
区间和容斥一下就可以了。
#include<cstdio>
#define LL long long
using namespace std;
const int maxn=200005;
int n,Q;
LL a[maxn],b[maxn];
inline int _read(){
int num=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();
return num;
}
int lowbit(int x){return x&(-x);}
void change(int x,int y){for (int i=x;i<=n;i+=lowbit(i)) a[i]+=y,b[i]+=(LL)(x-1)*y;}
LL ask(int x){LL num=0;for (int i=x;i;i-=lowbit(i)) num+=(LL)x*a[i]-b[i];return num;}
int main(){
freopen("exam.in","r",stdin);
freopen("exam.out","w",stdout);
n=_read();
for (int i=1;i<=n;i++){
int x=_read();
change(i,x);change(i+1,-x);
}
Q=_read();
while(Q--){
int d=_read(),L=_read(),R=_read(),x;
if (d==1){
x=_read();
change(L,x);change(R+1,-x);
}else printf("%lld\n",ask(R)-ask(L-1));
}
return 0;
}