给定一个长度为 N 的数列 A,以及 M 条指令,每条指令可能是以下两种之一:
C l r d,表示把 A[l],A[l+1],…,A[r] 都加上 d。
Q l r,表示询问数列中第 l∼r 个数的和。
对于每个询问,输出一个整数表示答案。
输入格式
第一行两个整数 N,M。
第二行 N 个整数 A[i]。
接下来 M 行表示 M 条指令,每条指令的格式如题目描述所示。
输出格式
对于每个询问,输出一个整数表示答案。
每个答案占一行。
数据范围
1≤N,M≤105,
|d|≤10000,
|A[i]|≤109
输入样例:
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
输出样例:
4
55
9
15
这道题是经典的线段树模型 , 线段树只能单点修改 和 区间查询, 所以我们要用到懒人标记来实现区间修改(懒人标记的含义是,子树还没有修改)
代码如下:
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
typedef long long LL;
struct Node{
int l , r;
LL sum , add;
} tr[4 * N];
int n , m ;
LL w[N] ;
void pushup(int u){
tr[u].sum = tr[ u << 1 ].sum + tr[u << 1 | 1].sum;
}
void pushdown(int u){
auto &root = tr[u];
auto &left = tr[u << 1];
auto &right = tr[u << 1 | 1];
if(root.add){
left.sum += (left.r - left.l + 1) * root.add ;
left.add += root.add;
right.sum += (right.r - right.l + 1) * root.add ;
right.add += root.add;
root.add = 0;
}
}
void build(int u , int l , int r){
if( l == r ) tr[u] = { l , r , w[l] , 0 };
else
{
int mid = l + r >> 1;
tr[u] = { l , r };
build( u << 1 , l , mid );
build( u << 1 | 1 , mid + 1 , r);
pushup(u);
tr[u].add = 0;
}
}
void modify(int u ,int l , int r , LL d ){
if(tr[u].l >= l && tr[u].r <= r){
tr[u].add += d;
tr[u].sum += (tr[u].r - tr[u].l + 1) * d;
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1 ;
if(l <= mid ) modify(u << 1 , l , r ,d );
if(r > mid ) modify(u << 1 | 1 , l , r , d );
pushup(u);
}
LL query(int u ,int l , int r ){
if(tr[u].l >= l && tr[u].r <= r) return tr[u].sum ;
pushdown(u);
LL sum = 0;
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) sum += query(u << 1 , l , r );
if(r > mid) sum += query(u << 1 | 1 , l , r );
pushup(u);
return sum;
}
int main(){
cin >> n >> m;
for(int i = 1 ; i <= n ; i ++ ) cin >> w[i] ;
build(1 , 1 , n);
while( m-- ){
char op[2] ;
int l , r;
cin >> op >> l >>r;
if(*op == 'Q'){
cout << query(1 , l , r) << endl ;
}
else{
LL d ;
cin >> d;
modify(1 , l , r , d );
}
}
}
树状数组的代码:
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
typedef long long LL;
LL tr1[N];// b[i]
LL tr2[N];// b[i] * i
int n , m ;
LL w[N];
int lowbit(int x){
return x & -x;
}
void add(LL tr[] , int x , LL d){
for(int i = x ; i <= n ; i += lowbit(i) )
tr[i] += d;
}
LL take(LL tr[] , int x ){
LL sum = 0 ;
for(int i = x ; i ; i -= lowbit(i) )
sum += tr[i];
return sum;
}
LL presum(int x){
return take(tr1 , x) * (x + 1) - take(tr2 , x);
}
int main(){
cin >> n >> m ;
for(int i = 1 ; i <= n ; i++ ){
cin >> w[i];
int b = w[i] - w[i - 1];
add(tr1 , i , b);
add(tr2 , i , (LL)i * b);
}
while( m-- ){
char op[2];
int l , r ;
cin >> op >> l >> r;
if(*op == 'Q'){
cout << presum(r) - presum(l - 1) << endl;
}
else{
LL d;
cin >> d;
add( tr1 , l , d);
add( tr2 , l , l * d);
add( tr1 , r + 1 , - d );
add( tr2 , r + 1 , - (r + 1) * d);
}
}
}
作者:月色
链接:https://www.acwing.com/activity/content/code/content/1276386/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。