线段树
Posted tecode
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树相关的知识,希望对你有一定的参考价值。
递归
#include <bits/stdc++.h>
#define LL long long
#define Pi acos(-1.0)
#define INF 2147483646
#define eps 1e-9
#define MS 100009
#define mss 17
using namespace std;
// Notice the data size
LL n; // 记录原数组个数
LL a[MS]; // 存原数组
LL p[MS*4]; // 数组实现树形结构 ,每一个节点对应一段区间
LL la[MS*4]; // 懒惰标记
void input() {
// 存储原数组
for(int i=1; i<=n; i++) cin >> a[i];
}
// 向上更新信息
void push_up(LL rt) {
p[rt] = p[rt<<1] + p[rt<<1|1];
}
// 下推标记
void push_down(LL rt, LL nl, LL nr) {
// 如果被标记
if(la[rt]){
// 下推标记
la[rt<<1] = la[rt<<1] + la[rt];
la[rt<<1|1] = la[rt<<1|1] + la[rt];
// 更新左右孩子信息
p[rt<<1] = p[rt<<1] + nl*la[rt];
p[rt<<1|1] = p[rt<<1|1] + nr*la[rt];
// 清除标记
la[rt] = 0;
}
}
// 建树
void build(LL l, LL r, LL rt) {
if(l == r){
// 在 *rt* 节点存储数据
p[rt] = a[l];
return;
}
LL m = (l+r)/2;
// 左右递归 寻找最后的叶子
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
// 向上更新信息
push_up(rt);
}
// 区间修改 (+)
void section_revise(LL L, LL R, LL l, LL r, LL x, LL rt) {
if(L<=l && r<=R){
// 修改该节点对应区间的值
p[rt] = p[rt] + x*(r-l+1);
// 修改懒惰标记
la[rt] = la[rt] + x;
return;
}
LL m = (l+r)/2;
// 下推标记
// 参数:节点, 左,右孩子元素个数
push_down(rt,m-l+1,r-m);
// 左右递归 ,寻找包含区间
if(m>=L) section_revise(L,R,l,m,x,rt<<1);
if(m< R) section_revise(L,R,m+1,r,x,rt<<1|1);
// 向上更新信息
push_up(rt);
}
// 区间求和
LL section_sum(LL L, LL R, LL l, LL r, LL rt) {
// 若查询到包含区间
if(L<=l && r<=R){
return p[rt];
}
LL m = (l+r)/2;
// 下推标记
push_down(rt,m-l+1,r-m);
// 记录答案
LL ans = 0;
if(m>=L) ans += section_sum(L,R,l,m,rt<<1);
if(m< R) ans += section_sum(L,R,m+1,r,rt<<1|1);
return ans;
}
// 数组现状输出
void output(LL l, LL r, LL rt){
if(l == r){
cout << p[rt] << " ";
return;
}
LL m = (l+r)/2;
// 下推标记
push_down(rt,m-l+1,r-m);
// 左右递归 寻找最后的叶子
output(l,m,rt<<1);
output(m+1,r,rt<<1|1);
}
int main() {
// 输入数据并建树
cin >> n;
input();
build(1,n,1);
// 区间修改
LL l ,r ,x;
cin >> l >> r >> x;
section_revise(l,r,1,n,x,1);
// 输出修改后结果
output(1,n,1);
cout << endl;
// 区间求和
cin >> l >> r;
cout << section_sum(l,r,1,n,1) << endl;
return 0;
}
以上是关于线段树的主要内容,如果未能解决你的问题,请参考以下文章