题目
思路
第一眼:树状数组暴力,区间和直接用前缀和做
好,70分
看来需要用数学推亿推了
树状数组的区间查询:查分
设
c
1
=
a
1
,
c
2
=
a
2
−
a
1
,
c
3
=
a
3
−
a
2
.
.
.
c
i
=
a
i
−
a
i
−
1
c_1=a_1,c_2=a_2-a_1,c_3=a_3-a_2...c_i=a_i-a_{i-1}
c1=a1,c2=a2−a1,c3=a3−a2...ci=ai−ai−1
特别地,
a
0
=
0
a_0=0
a0=0
如果用c表示出a来,那么可以发现
a
i
=
∑
j
=
1
i
c
j
a_i=\sum_{j=1}^ic_j
ai=j=1∑icj
所以得出前缀和
s
u
m
i
=
∑
j
=
1
i
∑
k
=
1
k
c
k
sum_i=\sum_{j=1}^i\sum_{k=1}^kc_k
sumi=j=1∑ik=1∑kck
=
(
c
1
)
+
(
c
1
+
c
2
)
+
.
.
.
+
(
c
1
+
c
2
+
.
.
.
+
c
i
)
=(c_1)+(c_1+c_2)+...+(c_1+c_2+...+c_i)
=(c1)+(c1+c2)+...+(c1+c2+...+ci)
=
i
∗
c
1
+
(
i
−
1
)
∗
c
2
+
.
.
.
+
1
∗
c
i
=i*c_1+(i-1)*c_2+...+1*c_i
=i∗c1+(i−1)∗c2+...+1∗ci
=
i
∗
(
c
1
+
c
2
+
.
.
.
+
c
i
)
−
(
0
∗
c
1
+
1
∗
c
2
+
.
.
.
(
i
−
1
)
∗
c
i
)
=i*(c_1+c_2+...+c_i)-(0*c_1+1*c_2+...(i-1)*c_i)
=i∗(c1+c2+...+ci)−(0∗c1+1∗c2+...(i−1)∗ci)
=
i
∗
∑
j
=
1
i
−
i
∗
∑
j
=
1
i
(
j
−
1
)
∗
c
j
=i*\sum_{j=1}^i-i*\sum_{j=1}^i(j-1)*c_j
=i∗j=1∑i−i∗j=1∑i(j−1)∗cj
然后分别用T1,T2存这两项
理论存在,实践开始
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lowbit(x) (x)&(-(x))
int n,m;
struct BIT{
static const int M=1e5+5;
int c[M];
void add(int x,int k) { while(x<=n) c[x]+=k,x+=lowbit(x); }
int query(int x) { int sum=0;while(x>0) sum+=c[x],x-=lowbit(x);return sum; }
}T1,T2;
signed main()
{
cin>>n>>m;
int a,c=0;
for(int i=1;i<=n;i++){
cin>>a;
c=a-c;
T1.add(i,c),T2.add(i,(i-1)*c);
c=a;
}
while(m--){
int if_case;
cin>>if_case;
int x,y,k;
switch (if_case){
case 1:cin>>x>>y>>k;T1.add(x,k),T1.add(y+1,-k),T2.add(x,k*(x-1)),T2.add(y+1,-k*(y+1-1));break;
case 2:cin>>x>>y;int sq=y*T1.query(y)-(x-1)*T1.query(x-1);int sh=T2.query(y)-T2.query(x-1);cout<<sq-sh<<endl;break;
}
}
return 0;
}