前言
树状数组解法:树状数组+区间更新区间查询
线段树对于区间更新区间查询的问题直接修改更新的函数即可,但每次更新时都把子区间一同更新这样其实是相对暴力的,因为更新完的区间我们可能一次都没有访问到!这里有个关于LazyTag的优化,其实就是让某个区间更新时,只更新其父区间,而对于其子区间我们打一个标记,其含义就是:这个区间的子区间还有更新的任务没做,等到以后的查询动用到它时再临时做(注意,这个标记打在父区间的节点上!可以记录这个区间没个位置要加上的数字),这样一来对于那些查询区间相对集中,而更新区间相对分散的测试数据效率是十分高的!(Ps:注意区间和可能爆int!要用long long
AC代码:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <deque>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <utility>
using namespace std;
const int maxn = (int)1e5+5;
typedef long long LL;
struct Node {
int l,r;
LL lazy_tag;
LL sum;
};
int n,q;
LL val[maxn];
Node LTree[maxn << 2];
void pushUp (int idx) {
LTree[idx].sum = LTree[idx << 1].sum + LTree[idx << 1 | 1].sum;
}
void pushDown (int idx) {
if (LTree[idx].lazy_tag) {
LTree[idx << 1].sum += (LTree[idx << 1].r- LTree[idx << 1].l + 1) * LTree[idx].lazy_tag;
LTree[idx << 1 | 1].sum += (LTree[idx << 1 | 1].r - LTree[idx << 1 | 1].l + 1) * LTree[idx].lazy_tag;
LTree[idx << 1].lazy_tag += LTree[idx].lazy_tag;
LTree[idx << 1 | 1].lazy_tag += LTree[idx].lazy_tag; //注意这几个都是+=
LTree[idx].lazy_tag = 0;
}
}
void Build (int l, int r, int idx) {
LTree[idx].l = l;
LTree[idx].r = r;
LTree[idx].lazy_tag = 0;
if (l == r) {
LTree[idx].sum = val[l];
return ;
}
int mid = l + ((r - l) >> 1);
Build(l, mid, idx << 1);
Build(mid + 1, r, idx << 1 | 1);
pushUp(idx);
}
void Modify (int l, int r, int num, int idx) { //[l,r] += num
if (l <= LTree[idx].l && r >= LTree[idx].r) {
LTree[idx].sum += (LTree[idx].r - LTree[idx].l + 1) * num;
LTree[idx].lazy_tag += num; //注意这里是+=,防止多次更新某个区间出错
return ;
}
pushDown(idx); //下放lazy_tag,因为后面要有新的lazy_tag诞生,并且下面的区间和要更新上来了
int mid = LTree[idx].l + ((LTree[idx].r - LTree[idx].l) >> 1);
if (l > mid) {
Modify(l, r, num, idx << 1 | 1);
}else if (r <= mid) {
Modify(l, r, num, idx << 1);
}else {
Modify(l, mid, num, idx << 1);
Modify(mid + 1, r, num, idx << 1 | 1);
}
pushUp(idx);
}
LL Query (int l, int r, int idx) {
if (l <= LTree[idx].l && r >= LTree[idx].r) {
return LTree[idx].sum;
}
pushDown(idx); //下放lazy_tag,因为我要查询其子区间的和了,那个和可能有值还没传下来,所以这步是必要的
int mid = LTree[idx].l + ((LTree[idx].r - LTree[idx].l) >> 1);
if (l > mid) {
return Query(l, r, idx << 1 | 1);
}else if (r <= mid) {
return Query(l, r, idx << 1);
}else {
return Query(l, mid, idx << 1) + Query(mid + 1, r, idx << 1 | 1);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int i,j,num;
string command;
while (cin >> n >> q) {
for (i = 1; i <= n; i++) {
cin >> val[i];
}
Build(1, n, 1);
while (q--) {
cin >> command >> i >> j;
switch (command.at(0)) {
case 'Q':
cout << Query(i, j, 1) << '\n';
break;
case 'C':
cin >> num;
Modify(i, j, num, 1);
break;
default:
break;
}
}
}
return 0;
}