传送门
问题:
给出一个随意序列,a1, a2, a3, a4, a5 ..... an
1.操作1,给出[ l, r ] , L = 区间的长度,
计算 ans = a[ l ] * ( L ) + a[ l+1 ] *(L-1) +....+ a[ r-1 ]*2+a[ r ]*1
2.操作2 ,把序列第 i 个数替换成 num 。
输入:
第一行:n,q (n个数字, q组操作)
第二行:n 个 数, 代表序列。
下面 q 行,每行 3 个数, 如果第一个数是 1 ,执行操作 1。。
如果第一个数是 2 ,执行操作 2 。
输出:
对于操作 1 , 输出一个数 ans 。
样例:
样例输入
5 3 1 2 3 4 5 1 1 3 2 5 0 1 4 5
样例输出
10 8
分析:
这道题可以转换成,区间更新,区间求和 的模板题。
对于题中给出的公式,例如序列:1 2 3 4 5。。
那么在区间[2 , 4]进行 操作 1 , 就是 ans = 2*3 + 3*2 + 4*1 ..
也就是 (2~4) + ( 2~3 )+ (2~2) 。。
那么,本题的重点转换就是!!!!!!!!!!!
用一个 前缀和 数组 b(和算上本位),来建一个线段树。
那么对于 [2, 4] ,区间,那么就是 线段树的区间求和! 假设这一步的结果是 t !!!!!
那么最终的 ans = t - b[ l - 1 ] * len.!!!! 这里的 len 为 小区间的长度。
比如 ,对于这一个例子,b2 = (1~2).. b3 = (1~3)... b4 = (1~4), 。。
比起需要求的 结果,多了 三个(1~1). 。仔细想想, 重复计算的,就是 b[ l-1 ]~~
重复计算的次数,就是小区间的长度。。
对于点更新,在前缀和数组中,就是更新 [i , n] 的值, 看看是增加了还是减少了,~~~
也就是区间更新
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 1e5+10;
const int MAXN1 = 4*1e5+10;
LL a[MAXN];
LL b[MAXN];
LL sum[MAXN1];
LL add[MAXN1];
void pushup(LL root)
{
sum[root] = sum[root*2] + sum[root*2+1];
}
void build(LL L,LL R,LL rt)
{
add[rt] = 0;
if(L == R)
{
sum[rt] = b[L];
return ;
}
LL M = (L+R)>>1;
build(L,M,rt*2);
build(M+1,R,rt*2+1);
pushup(rt);
}
void pushdown(LL rt, LL len)
{// 标记下移
LL Lson = rt<<1;
LL Rson = rt<<1|1;
add[Lson] += add[rt];
add[Rson] += add[rt];
sum[Lson] += (len - (len>>1)) * add[rt];
sum[Rson] += (len >> 1 ) * add[rt];
// 本层标记取消
add[rt] = 0;
}
LL query(LL rt, LL l,LL r, LL L ,LL R)
{
if(l == L && r== R)
return sum[rt];
if(add[rt])
pushdown(rt,R-L+1);
LL ans = 0;
LL M = (L+R)>>1;
if(r <= M)
ans += query(rt*2, l, r, L, M);
else if(l > M)
ans += query(rt*2+1,l,r,M+1,R);
else
{
ans += query(rt*2, l, M, L, M);
ans += query(rt*2+1,M+1,r,M+1,R);
}
return ans;
}
/* l~r 区间每个数加num **/
void update(LL rt, LL l, LL r, LL L, LL R, LL num)
{
if(l <= L && R <= r)
{
sum[rt] += (R-L+1)*num;
add[rt] += num;
}
else
{
LL M = (L + R) >> 1;
if(add[rt])
pushdown(rt,r-l+1);
if(l <= M)
update(rt<<1, l, r, L, M, num);
if(r > M)
update(rt<<1|1,l,r,M+1,R, num);
pushup(rt);
}
return ;
}
int main()
{
ios::sync_with_stdio(false);
LL n,q;
cin >> n >> q;
for(LL i = 1; i <= n; i++)
cin >> a[i];
b[1] = a[1];
for(LL i = 2; i <= n; i++)
b[i] = a[i]+b[i-1];
build(1,n,1);
while(q--)
{
LL t,l,r,t1;
cin >> t >> l >> r;
if(l != 1)
t1 = (r-l+1) * query(1,l-1,l-1,1,n);
else
t1 = 0;
//区间求和
if( t == 1 )
{
LL ans = query(1,l,r,1,n);
ans -= t1;
cout << ans << endl;
}
//区间更新
else if( t == 2 )
{
LL num = r-a[l];
a[l] = r;
r = n;
update(1,l,r,1,n,num);
}
}
// system("pause");
return 0;
}