传送门
这个主要用到一种方法:不是每次更新都要从根节点更新到叶子节点,更新到枝干就行,在查找的时候在去处理
代码:
#include<iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <functional>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <algorithm>
#define ll long long
#define mes(x,y) memset(x,y,sizeof(x))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
ll GCD(ll a, ll b) {//最大公约数
return b == 0 ? a : GCD(b, a % b);
}
ll Power(ll a, ll b, ll p) { //计算(a^b)%p;
ll ans = 1;
while (b) {
if (b & 1) //等价于b%2,判断b的奇偶性
ans = ans * a % p; //如果为奇数,证明该位为1,需要乘上a
a = a * a % p; //计算a^(2^i)
b >>= 1; //等价于b/=2;
}
return ans;
}
bool isprime(int num)
{
if (num == 2 || num == 3)
return true;
if (num % 6 != 1 && num % 6 != 5)
return false;
int t = sqrt((double)num);
for (int i = 5; i <= t; i += 6)
{
if (num % i == 0 || num % (i + 2) == 0)
return false;
}
return true;
}
const ll INFF = 2000000;
struct node {
ll begin = 0, end = 0, flag = 0;
ll sum = 0, inc = 0;
ll Mid1() {
return ((begin + end) / 2);
}
ll Mid2() {
return((begin + end) / 2 + 1);
}
ll Left() {
return (flag * 2);
}
ll Right() {
return (flag * 2 + 1);
}
}tree[400010];
void BuildTree(ll flag, ll begin, ll end) {
tree[flag].inc = tree[flag].sum = 0;
tree[flag].begin = begin;
tree[flag].end = end;
tree[flag].flag = flag;
//cout << flag << ":" << tree[flag].begin << " " << tree[flag].end << " " << tree[flag].Mid1() << endl;
if (begin == end)return;
BuildTree(tree[flag].Left(), begin, tree[flag].Mid1());
BuildTree(tree[flag].Right(), tree[flag].Mid2(), end);
}
void Insert(ll flag, ll set, ll value) {
if (tree[flag].begin == set && tree[flag].end == set) {
tree[flag].sum = value;//重点
return;
}
tree[flag].sum += value;//重点
if (set <= tree[flag].Mid1()) {
Insert(tree[flag].Left(), set, value);
}
else {
Insert(tree[flag].Right(), set, value);
}
}
void Add(ll flag, ll begin, ll end, ll value) {
if (tree[flag].begin == begin && tree[flag].end == end) {
tree[flag].inc += value;//重点
return;
}
tree[flag].sum += (end - begin + 1) * value;//重点
if (end <= tree[flag].Mid1()) {
Add(tree[flag].Left(), begin, end, value);
}
else if (begin >= tree[flag].Mid2()) {
Add(tree[flag].Right(), begin, end, value);
}
else {
Add(tree[flag].Left(), begin, tree[flag].Mid1(), value);
Add(tree[flag].Right(), tree[flag].Mid2(), end, value);
}
}
ll Query(ll flag, ll begin, ll end) {
if (tree[flag].begin == begin && tree[flag].end == end) {
return tree[flag].sum + (end - begin + 1) * tree[flag].inc;
}
tree[flag].sum += (tree[flag].end - tree[flag].begin + 1) * tree[flag].inc;
tree[tree[flag].Left()].inc += tree[flag].inc;
tree[tree[flag].Right()].inc += tree[flag].inc;
tree[flag].inc = 0;
if (end <= tree[flag].Mid1()) {
Query(tree[flag].Left(), begin, end);
}
else if (begin >= tree[flag].Mid2()) {
Query(tree[flag].Right(), begin, end);
}
else {
return Query(tree[flag].Left(), begin, tree[flag].Mid1())+ Query(tree[flag].Right(), tree[flag].Mid2(), end);
}
}
int main() {
//FAST_IO;
ll n, m, k, i, j, vb;
while (cin >> n >> m) {
BuildTree(1, 1, n);
for (i = 1; i <= n; i++) {
cin >> j;
Insert(1, i, j);
}
ll x, y,z;
string a;
for (i = 0; i < m; i++) {
cin >> a;
if (a == "Q") {
cin >> x >> y;
cout << Query(1, x, y) << endl;
}
else {
cin >> x >> y >> z;
Add(1, x, y, z);
}
}
}
}