(线段树,add懒标记)洛谷模板题
原题链接:
洛谷模板题
题目:
如题,已知一个数列,你需要进行下面两种操作:
1、将某区间每一个数加上 k。
2、求出某区间每一个数的和。
输入格式:
第一行包含两个整数 n,m,分别表示该数列数字的个数和操作的总个数。
第二行包含 n 个用空格分隔的整数,其中第 i 个数字表示数列第 i 项的初始值。
接下来 m 行每行包含 3 或 4 个整数,表示一个操作,具体如下:
1 x y k 表示将[x, y]区间内的数都加上k
2 x y 表示查询[x, y]区间内的总合
输出格式:
输出包含若干行整数,即为所有操作 2 的结果。
输入 #1??????输出 #1
5 5 ????????11
1 5 4 2 3 ?????8
2 2 4????????20
1 2 3 2
2 3 4
1 1 5 1
2 1 4
说明:
所有数据范围:1 ≤ n, m ≤ 1e5
答案在long long 范围内。
思路:
??这题为什么要用线段树来写呢,那就是因为区间修改,区间查询了吧,如果是区间修改,单点查询,
用树状数组他不香吗,那么线段树的区间修改又涉及到了懒标记的运用。
?线段树的区间操作可以使用懒标记来优化时间复杂度,具体实现就得写一个pushdown函数,作用是将
懒标记的值传给他的儿子,这样就可以将查询前的n步操作化为一步,大大优化了时间复杂度,具体实现并
不复杂,重要的还是多练(我还是太菜了)。
?
#include
using namespace std;
#define endl '\n'
#define int long long
typedef pair PII;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 10;
int n, m;
int w[N];
struct Node{
int l, r;
int sum, add;
}tr[N << 2];
void pushup(int u){
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void pushdown(int u){ //pushdown操作里的sum += x我开始写成了 =,所有改了好久,痛心疾首
if(tr[u].add){
tr[u << 1].sum += (tr[u << 1].r - tr[u << 1].l + 1) * tr[u].add;
tr[u << 1 | 1].sum += (tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1) * tr[u].add;
tr[u << 1].add += tr[u].add;
tr[u << 1 | 1].add += tr[u].add;
tr[u].add = 0;
}
}
void build(int u, int l, int r){
tr[u].l = l, tr[u].r = r;
if(l == r) tr[u].sum = w[l];
else{
int mid = l + r >> 1;
build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r);
pushup(u);
}
}
void modify(int u, int l, int r, int k){ //包含在指定区间内再操作,包含的运算符想清楚再写,就不会debug这么久
if(tr[u].l >= l && tr[u].r <= r){
tr[u].sum += (tr[u].r - tr[u].l + 1) * k;
tr[u].add += k;
}
else{
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) modify(u << 1, l, r, k);
if(r > mid) modify(u << 1 | 1, l, r, k);
pushup(u);
}
}
int query(int u, int l, int r){
if(tr[u].l >= l && tr[u].r <= r){
//cout << tr[u].l << " " << tr[u].r << endl;
return tr[u].sum;
}
else{
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
int res = 0;
if(l <= mid) res += query(u << 1, l, r);
if(r > mid) res += query(u << 1 | 1, l, r);
return res;
}
}
signed main(void){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; i++)
cin >> w[i];
build(1, 1, n);
for(int i = 1; i <= m; i++){
int op, l, r, k;
cin >> op >> l >> r;
if(op == 1){
cin >> k;
modify(1, l, r, k);
}
else{
cout << query(1, l, r) << endl;
}
}
return 0;
}