题目
题目链接:http://poj.org/problem?id=3468
题目来源:《挑战》例题。
简要题意:区间内数全加上某数或者求区间内的和。
题解
经典的区间更新区间求和。
用线段树的话需要加上lazy标记,每段根据长度去加上多来的值来更新。
树状数组写起来代码量更短,运行速度也更快,但更难理解。
写法的话就是维护两个树状数组。
一个表示总和,还有一个表示增量,援引《挑战》设 s(i),s′(i) 为更新前后 ∑j=1iaj 。
假设增加的值为 x ,区间为
[l,r] 。
s′(i)=⎧⎩⎨⎪⎪s(i) i<ls(i)+x⋅i−x(l−1) l⩽i⩽rs(i)+x(r−l+1) i>r将公式拆成两个东西来维护就能够维护值了。
线段树代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
// head
const int N = 1e5+5;
struct SegmentTree {
#define lson (rt<<1)
#define rson ((rt<<1)|1)
#define MID ((L+R)>>1)
#define lsonPara lson, L, MID
#define rsonPara rson, MID+1, R
const static int TN = N << 2;
LL tree[TN];
int lazy[TN];
void pushUp(int rt) {
tree[rt] = tree[lson] + tree[rson];
}
void pushDown(int rt, int L, int R) {
if (lazy[rt]) {
lazy[lson] += lazy[rt];
lazy[rson] += lazy[rt];
tree[lson] += LL(MID - L + 1) * lazy[rt];
tree[rson] += LL(R - MID) * lazy[rt];
lazy[rt] = 0;
}
}
void build(int rt, int L, int R) {
lazy[rt] = 0;
if (L == R) {
scanf("%I64d", tree+rt);
} else {
build(lsonPara);
build(rsonPara);
pushUp(rt);
}
}
void modify(int rt, int L, int R, int l, int r, int v) {
if (l > R || r < L) return;
if (l <= L && r >= R) {
lazy[rt] += v;
tree[rt] += LL(R - L + 1) * v;
} else {
pushDown(rt, L, R);
modify(lsonPara, l, r, v);
modify(rsonPara, l, r, v);
pushUp(rt);
}
}
LL query(int rt, int L, int R, int l, int r) {
if (l > R || r < L) return 0;
if (l <= L && r >= R) return tree[rt];
pushDown(rt, L, R);
return query(lsonPara, l, r) + query(rsonPara, l, r);
}
};
SegmentTree st;
char s[5];
int main() {
int n, m, a, b, c;
while (scanf("%d%d", &n, &m) == 2) {
st.build(1, 1, n);
for (int i = 0; i < m; i++) {
scanf("%s%d%d", s, &a, &b);
if (s[0] == 'Q') {
printf("%I64d\n", st.query(1, 1, n, a, b));
} else {
scanf("%d", &c);
st.modify(1, 1, n, a, b, c);
}
}
}
return 0;
}
树状数组代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
// head
struct BIT {
#define T LL
static const int N = 500005;
T tree[N] ;
inline int lowbit(int x) {
return x&(-x);
}
void add(int x, T add, int n) {
for (int i = x; i <= n; i += lowbit(i)) {
tree[i] += add;
}
}
T sum(int x) {
T ans = 0;
for (int i = x; i > 0; i -= lowbit(i)) {
ans += tree[i];
}
return ans;
}
void clear(int n) {
for (int i = 1; i <= n; i++) {
tree[i] = 0;
}
}
#undef T
};
BIT bt0, bt1;
char s[5];
int main() {
int n, m, a, b, c, x;
while (scanf("%d%d", &n, &m) == 2) {
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
bt0.add(i, x, n);
}
for (int i = 0; i < m; i++) {
scanf("%s%d%d", s, &a, &b);
if (s[0] == 'Q') {
LL ans = bt0.sum(b) - bt0.sum(a-1);
ans += b * bt1.sum(b) - (a-1) * bt1.sum(a-1);
printf("%I64d\n", ans);
} else {
scanf("%d", &c);
bt0.add(b+1, LL(b) * c, n);
bt0.add(a, -LL(a-1) * c, n);
bt1.add(b+1, -c, n);
bt1.add(a, c, n);
}
}
bt0.clear(n);
bt1.clear(n);
}
return 0;
}