題目描述
如題,已知一個數列 {ai}\{a_i\}{ai?},你需要進行下面兩種操作:
- 將某區間每一個數加上 kkk。
- 求出某區間每一個數的和。
輸入格式
第一行包含兩個整數 n,mn, mn,m,分別表示該數列數字的個數和操作的總個數。
第二行包含 nnn 個用空格分隔的整數 aia_iai?,其中第 iii 個數字表示數列第 iii 項的初始值。
接下來 mmm 行每行包含 333 或 444 個整數,表示一個操作,具體如下:
1 x y k
:將區間 [x,y][x, y][x,y] 內每個數加上 kkk。2 x y
:輸出區間 [x,y][x, y][x,y] 內每個數的和。
輸出格式
輸出包含若干行整數,即為所有操作 2 的結果。
輸入輸出樣例 #1
輸入 #1
5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
輸出 #1
11
8
20
說明/提示
對于 15%15\%15% 的數據:n≤8n \le 8n≤8,m≤10m \le 10m≤10。
對于 35%35\%35% 的數據:n≤103n \le {10}^3n≤103,m≤104m \le {10}^4m≤104。
對于 100%100\%100% 的數據:1≤n,m≤1051 \le n, m \le {10}^51≤n,m≤105,ai,ka_i,kai?,k 為正數,且任意時刻數列的和不超過 2×10182\times 10^{18}2×1018。
【樣例解釋】
solution
線段樹是一種常用的數據結構,實現區間查詢和區間修改,時間和空間復雜度都是O(nlogn)O(nlogn)O(nlogn)
其基本原理是用一個二叉樹點維護一個區間的數據,然后它的兩個字節點各負責半個區間,將統計信息匯總給該節點
代碼
#include <sstream>
#include "iostream"
#include "cmath"
#include "vector"
#include "algorithm"using namespace std;
const int N = 1e5 + 5;int n;
long long b[N];struct node {long long sum, tag;
} a[4 * N];// 將父節點的 tag 信息向下分攤
void push_down(int rt, int l, int r) {int m = r + l >> 1;a[rt * 2].sum += a[rt].tag * (m - l + 1);a[rt * 2].tag += a[rt].tag;a[rt * 2 + 1].sum += a[rt].tag * (r - m);a[rt * 2 + 1].tag += a[rt].tag;a[rt].tag = 0;
}void push_up(int rt) {a[rt].sum = a[rt * 2].sum + a[rt * 2 + 1].sum;
}void build(int rt, int l, int r) {a[rt].tag = 0;if (l == r) {a[rt].sum = b[l];return;}int m = l + r >> 1;build(rt * 2, l, m);build(rt * 2 + 1, m + 1, r);push_up(rt);
}void update(int rt, long long k, int l, int r, int L, int R) { // l, r 是 rt管理的區間, L R是修改的區間, k 是修改的量// 整個區間都要增加kif (L <= l && r <= R) {a[rt].sum += (r - l + 1) * k;a[rt].tag += k;return;}push_down(rt, l, r); // tag 向下傳遞int m = l + r >> 1;if (L <= m) update(rt * 2, k, l, m, L, R);if (R > m) update(rt * 2 + 1, k, m + 1, r, L, R);push_up(rt); // sum 向上匯總
}long long query(int rt, int l, int r, int L, int R) {// 整個區間都要if (L <= l && r <= R) {return a[rt].sum;}push_down(rt, l, r);int m = l + r >> 1;long long s = 0;if (L <= m) s += query(rt * 2, l, m, L, R);if (R > m) s += query(rt * 2 + 1, m + 1, r, L, R);return s;
}int main() {int m;cin >> n >> m;for (int i = 1; i <= n; i++) cin >> b[i];build(1, 1, n);for (int i = 0; i < m; i++) {int op, l, r;long long k;cin >> op >> l >> r;if (op == 1) {cin >> k;update(1, k, 1, n, l, r);} else {cout << query(1, 1, n, l, r) << endl;}}}