3468 -- A Simple Problem with Integershttp://poj.org/problem?id=3468
线段树:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#define x first
#define y second
using namespace std;
typedef long long ll;
const int MAX = 100004;
ll add[4 * MAX] = { 0 }, sum[4 * MAX] = { 0 };
void updateChildren(int root, int len) { // 更新root的子节点
if (add[root]) {
int lchild = root << 1;
add[lchild] += add[root];
add[lchild + 1] += add[root];
int half = len >> 1;
sum[lchild] += (len - half) * add[root];
sum[lchild + 1] += half * add[root];
add[root] = 0; // 取消标记
}
}
void buildTree(int left, int right, int root) {
if (left == right) { // 叶节点
cin >> sum[root]; // sum[root]记录root的区间和
return;
}
int mid = (left + right) >> 1;
int lchild = root << 1;
buildTree(left, mid, lchild);
buildTree(mid + 1, right, lchild + 1);
sum[root] = sum[lchild] + sum[lchild + 1];
}
void update(int a, int b, ll c, int left, int right, int root) {
if (a > right || b < left) { // 没有交集
return;
}
int len = right - left + 1;
if (a <= left && b >= right) { // [left, right]是[a, b]的子集
sum[root] += len * c; // 更新root的区间和
add[root] += c;
return;
}
updateChildren(root, len);
int mid = (left + right) >> 1;
int lchild = root << 1;
update(a, b, c, left, mid, lchild);
update(a, b, c, mid + 1, right, lchild + 1);
sum[root] = sum[lchild] + sum[lchild + 1];
}
ll query(int a, int b, int left, int right, int root) { // 区间求和
if (a > right || b < left) { // 没有交集
return 0;
}
if (a <= left && b >= right) { // [left, right]是[a, b]的子集
return sum[root];
}
updateChildren(root, right - left + 1);
int mid = (left + right) >> 1;
int lchild = root << 1;
ll ans = 0;
ans += query(a, b, left, mid, lchild);
ans += query(a, b, mid + 1, right, lchild + 1);
return ans;
}
int main() {
// system("chcp 65001");
cin.tie(0);
cout.tie(0);
freopen("C:/Users/zhaochen/Desktop/input.txt", "r", stdin);
int n, m;
cin >> n >> m;
buildTree(1, n, 1);
while (m--) {
string str;
cin >> str;
int a, b;
ll c;
if (str == "C") {
cin >> a >> b >> c;
update(a, b, c, 1, n, 1);
} else {
cin >> a >> b;
cout << query(a, b, 1, n, 1) << endl;
}
}
return 0;
}
树状数组的区间修改:原来树状数组可以这么简单?https://mp.weixin.qq.com/s/rciN3FySkvuf1CjWoFg84w
#include <iostream>
#include <string>
using namespace std;
typedef long long ll;
const int MAX = 100004;
int n;
ll sum1[MAX] = { 0 }, sum2[MAX] = { 0 };
ll lowbit(ll x) {
return x & -x;
}
void update(ll* sum, int index, ll c) {
while (index <= n) {
sum[index] += c;
index += lowbit(index);
}
}
void updateRange(int left, int right, ll c) {
right++;
update(sum1, left, c);
update(sum1, right, -c);
update(sum2, left, c * left);
update(sum2, right, -c * right);
}
ll query(ll* sum, int index) {
ll res = 0;
while (index > 0) {
res += sum[index];
index -= lowbit(index);
}
return res;
}
ll queryRange(int left, int right) {
left--; // [1, right]的区间减去[1, left-1]的区间
ll sumL = (left + 1) * query(sum1, left) - query(sum2, left);
ll sumR = (right + 1) * query(sum1, right) - query(sum2, right);
return sumR - sumL;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
ll a;
cin >> a;
updateRange(i, i, a);
}
while (m--) {
string str;
cin >> str;
int a, b;
ll c;
if (str == "C") {
cin >> a >> b >> c;
updateRange(a, b, c);
} else {
cin >> a >> b;
cout << queryRange(a, b) << endl;
}
}
return 0;
}