题目
题解思路
这题也可以用线段树的懒标记做。
这里用的是进阶版树状数组
上一题,我们是直接存原数组的差分数组的树状数组来解决区间加法的问题,
这一次我们再开一个ia[i]的差分数组的树状数组。按照上面推导的公式就能求出原数组的前缀和了。
add1( tre1 , t2 , t4 );
add1( tre1 , t3 + 1 , -t4 );
add1( tre2 , t2 , t2*t4 );
add1( tre2 , t3 + 1 , -t4*(t3 + 1 ) );
这一步对ia[i]的差分树状数组的区间加法操作有点看不懂,但写出又是对的。
记住吧。。。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
#include <unordered_map>
using namespace std;
const int INF = 0x3f3f3f3f;
long long tre1[100010] ;
long long tre2[100010] ;
long long a[100010] ;
int n , m ;
int lowbit( int x )
{
return x & (-x) ;
}
void add1( long long tre [] , long long x , long long y )
{
for (int i = x ; i <= n ; i += lowbit(i) )
tre[i] += y ;
}
long long sum( long long tre[] , long long x )
{
long long res = 0 ;
for (int i = x ; i ; i -= lowbit(i) )
res += tre[i] ;
return res ;
}
long long getsum( long long r )
{
return sum( tre1 , r)*(r+1) - sum(tre2 , r );
}
int main ()
{
ios::sync_with_stdio(false);
cin >> n >> m ;
for (int i = 1 ; i <= n ; i++ )
cin>>a[i];
for (int i = 1 ; i <= n ; i++ )
{
long long tt = a[i] - a[i-1] ;
add1(tre1 , i , tt ) ;
add1(tre2 , i , i*tt ) ;
}
for (int i = 1 ; i <= m ; i++ )
{
string t1 ;
long long t2 , t3 , t4 ;
cin>>t1;
if ( t1[0] == 'Q')
{
cin >> t2 >> t3 ;
cout<<getsum(t3) - getsum(t2-1)<<"\n";
}else
{
cin >> t2 >> t3 >> t4 ;
add1( tre1 , t2 , t4 );
add1( tre1 , t3 + 1 , -t4 );
add1( tre2 , t2 , t2*t4 );
add1( tre2 , t3 + 1 , -t4*(t3 + 1 ) );
}
}
return 0 ;
}