题意
很简答就是每次查询 (L,R)的时候 ,查询
a[L]∗(R−L+1)+a[L+1]∗(R−L−1)+a[L+2]∗(R−L−2)....a[R]∗1
a
[
L
]
∗
(
R
−
L
+
1
)
+
a
[
L
+
1
]
∗
(
R
−
L
−
1
)
+
a
[
L
+
2
]
∗
(
R
−
L
−
2
)
.
.
.
.
a
[
R
]
∗
1
,还有修改值
思路
我们可以看出
a[l]×L+a[l+1]×(L−1)+⋯+a[r−1]×2+a[r]
a
[
l
]
×
L
+
a
[
l
+
1
]
×
(
L
−
1
)
+
⋯
+
a
[
r
−
1
]
×
2
+
a
[
r
]
这个东西其实就是前缀和的前缀和啊 。。。
a[1]+a[1]+a[2]+a[1]+a[2]+a[3]+a[1]+a[2]+a[3]+a[4]=4∗a[1]+3∗a[2]+2∗a[3]+a[4]
a
[
1
]
+
a
[
1
]
+
a
[
2
]
+
a
[
1
]
+
a
[
2
]
+
a
[
3
]
+
a
[
1
]
+
a
[
2
]
+
a
[
3
]
+
a
[
4
]
=
4
∗
a
[
1
]
+
3
∗
a
[
2
]
+
2
∗
a
[
3
]
+
a
[
4
]
那么我们线段树就维护前缀和的前缀和就行了,对于查询来说,比如说我我们查
[4,6]
[
4
,
6
]
,那其实就是
a[4]+a[4]+a[5]+a[4]+a[5]+a[6],那我们查询的前缀和的前缀和的和是多少呢?a[1]+a[2]+a[3]+a[4]+a[1]+a[2]+a[3]+a[4]+a[5]+a[1]+a[2]+a[3]+a[4]+a[5]+a[6]
a
[
4
]
+
a
[
4
]
+
a
[
5
]
+
a
[
4
]
+
a
[
5
]
+
a
[
6
]
,
那
我
们
查
询
的
前
缀
和
的
前
缀
和
的
和
是
多
少
呢
?
a
[
1
]
+
a
[
2
]
+
a
[
3
]
+
a
[
4
]
+
a
[
1
]
+
a
[
2
]
+
a
[
3
]
+
a
[
4
]
+
a
[
5
]
+
a
[
1
]
+
a
[
2
]
+
a
[
3
]
+
a
[
4
]
+
a
[
5
]
+
a
[
6
]
,可以看出他多了什么? 他多了
a[1]+a[2]+a[3]+a[1]+a[2]+a[3]+a[1]+a[2]+a[3]
a
[
1
]
+
a
[
2
]
+
a
[
3
]
+
a
[
1
]
+
a
[
2
]
+
a
[
3
]
+
a
[
1
]
+
a
[
2
]
+
a
[
3
]
,他多了一个
(R−L+1)∗(a[1]+a[2]+a[3])
(
R
−
L
+
1
)
∗
(
a
[
1
]
+
a
[
2
]
+
a
[
3
]
)
,那么查询其实就是query(l,r) - (r-l+1) *query(l-1,l-1),对于更新操作怎么办?我们把第4个位置上面的值+1,那其实就是所有的a[4] + 1,就是(pos,n)的这个区间我们都+1,这就是一个裸的区间更新和区间查询
代码
#include <bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define int long long
using namespace std;
const int maxn = 1e5+10;
long long a[maxn] , sum[maxn];
long long tree[maxn<<2] ,add[maxn<<2];
struct Tree
{
void pushup(int rt)
{
tree[rt] = tree[rt<<1] + tree[rt<<1|1];
}
void pushdown(int l,int r,int rt)
{
if(!add[rt]) return ;
int m = (l+r)>>1;
add[rt<<1] += add[rt];
add[rt<<1|1] += add[rt];
tree[rt<<1] += add[rt] *(m-l+1);
tree[rt<<1|1] += add[rt] * (r-m);
add[rt] = 0;
}
void build(int l,int r,int rt)
{
if(l == r) {tree[rt] = sum[l] ; return ;}
int m = (l+r)>>1;
build(lson);
build(rson);
pushup(rt);
}
void update(int L,int R,long long val, int l,int r,int rt)
{
if(l >= L && R >= r)
{
tree[rt] += (r-l+1)*val;
add[rt] += val;
return ;
}
pushdown(l,r,rt);
int m = (l+r)>>1;
if(m >= L) update(L,R,val,lson);
if(m < R) update(L,R,val,rson);
pushup(rt);
}
long long query(int L,int R,int l,int r,int rt)
{
if(l >= L && R >= r) return tree[rt];
pushdown(l,r,rt);
int m = (l+r)>>1;
long long ret = 0 ;
if(m >= L) ret += query(L,R,lson);
if(m < R) ret += query(L,R,rson);
return ret;
}
};
signed main()
{
int n,q;
while(scanf("%lld%lld",&n,&q)!=EOF)
{
memset(sum,0,sizeof(sum));
memset(tree,0,sizeof(tree));
memset(add,0,sizeof(add));
sum[0] = 0;
Tree A;
for(int i = 1 ; i <= n ; i++)
{
scanf("%lld",&a[i]);
sum[i] = sum[i-1] + a[i];
}
A.build(1,n,1);
while(q--)
{
int op,l,r;
scanf("%lld%lld%lld",&op,&l,&r);
if(op == 1)
{
long long ans = 0;
if(l == 1) ans = A.query(l,r,1,n,1);
else
{
ans = A.query(l,r,1,n,1) - (r-l+1) * A.query(l-1,l-1,1,n,1);
}
cout<<ans<<endl;
}
else
{
A.update(l,n,r-a[l],1,n,1);
a[l] = r;
}
}
}
}