題目描述
You have N integers, A1, A2, … , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
輸入描述
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000. The
second line contains N numbers, the initial values of A1, A2, … ,
AN. -1000000000 ≤ Ai ≤ 1000000000. Each of the next Q lines represents
an operation. “C a b c” means adding c to each of Aa, Aa+1, … , Ab.
-10000 ≤ c ≤ 10000. “Q a b” means querying the sum of Aa, Aa+1, … , Ab.
輸出描述
You need to answer all Q commands in order. One answer in a line.
題解
建議若想學習樹狀數組區間操作+區間和的同學,可以先去學習樹狀數組區間操作+單點操作。
假設數組a是原數組,b是a的差分數組,由前綴和的定義,我們求前n個元素的和,即
先對原數組a進行差分,得到差分數組b,纔對b[i]和b[i]*i分別維護一個樹狀數組tb和tc,
而l到r的和變爲
[(r + 1) * sum(tb, r) - sum(tc, r)]-[(l + 1) * sum(tb, l) - sum(tc, l)]
需要注意的是開vector<>後靠resize()維護大小會卡在60%
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
using namespace std;
ll a[100005],b[100005];//a爲原數組,b爲a的差分數組
ll tb[100005],tc[100005]; //b[i]和b[i]*i分別維護的一個樹狀數組
int n,m; //n爲樹狀數組大小
int lowbit(int x)
{
return x&-x;
}
void add(int i,ll x)
{
ll v=i*x;
while(i<=n)
{
tb[i]+=x;
tc[i]+=v;
i+=lowbit(i);
}
}
void range_add(int l,int r,ll x)
{
add(l,x);
add(r+1,-x);
}
ll sum_t(ll arr[],int i)
{
ll res=0;
while(i>0)
{
res+=arr[i];
i-=lowbit(i);
}
return res;
}
ll sum(int i)
{
return (i+1)*sum_t(tb,i)-sum_t(tc,i);
}
ll range_sum(int l,int r)
{
return sum(r)-sum(l-1);
}
int main() {
ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
b[i]=a[i]-a[i-1];
for(int i=1;i<=n;i++)
add(i,b[i]);
while(m--)
{
char c;cin>>c;
if(c=='Q'){
int x,y;cin>>x>>y;
cout<<range_sum(x,y)<<endl;
}
else if(c=='C'){
ll x,y,z;cin>>x>>y>>z;
range_add(x,y,z);
}
}
return 0;
}