一套适合自己风格的线段树模板整理
经过一天半的煎熬,刚开始头疼的不行,实在想不通,到现在线段树终于像是入坑了,在网上找了好多资料,终于能结合人家的写一套适合我风格的模板。现在来记录下我的一些理解和代码,在以后含糊的时候返回来看看。推荐视频:b站 正月点灯笼 思路很容易理解,但代码难模仿,SWPU-ACM的代码还是容易模仿的。还有强大的CSDN上有很多详细的讲解。
我的代码主要时使用一个结构体代表树,我觉得用结构体能够更好地展示这个树的特点,和每一个结点的内容。在写的过程中保存了好多测试截图的,不过现在懒得上传了。。。该有的注释我加到代码旁边。
以下函数包括:
void build(int rt, int l, int r) (建树)
rt代表每次要创建的根节点,l和r为这个树上表示的左右端点值
void update(int rt, int p, int val) (单点修改)
rt仍然为树的根节点,p为要修改的位置,val为新值
void update(int rt, int l, int r, int c) (区间修改)
此函数作用为在l到r这一区间内,对每个值增加c
int query(int rt, int p) (单点查询)
查询p点的值
int query(int rt, int l, int r) (区间查询)
查询l到r这一区间内的信息,可查询sum,max,min···
void down(int rt) (懒标记下传)
当用到懒标记(区间修改)之后,再次进行区间或者单点查询时,就需要进行懒标记下传。
线段树模板如下(懒标记):
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
const int maxn = 1e5;
int a[maxn];
struct node{
int l, r;
int sum;
int lazy;
}tree[4*maxn];
int n, m;
void up(int rt){
tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}
void down(int rt){
if(tree[rt].lazy){
tree[rt<<1].lazy += tree[rt].lazy;
tree[rt<<1|1].lazy += tree[rt].lazy;
tree[rt<<1].sum += tree[rt].lazy * (tree[rt<<1].r-tree[rt<<1].l+1);
tree[rt<<1|1].sum += tree[rt].lazy * (tree[rt<<1|1].r-tree[rt<<1|1].l+1);
tree[rt].lazy = 0;
}
}
void build(int rt, int l, int r){
tree[rt].l = l, tree[rt].r = r;
tree[rt].lazy = 0;
// 如果当前节点记录的区间只有一个值,说明找到了叶子结点,直接赋值
// 否则递归构造左右子树,最后回溯的时候给当前节点赋值
if(l == r){
tree[rt].sum = a[l];
return ;
}
int mid = (l + r) >> 1;
build(rt<<1, l, mid);
build(rt<<1|1, mid+1, r);
tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}
/*
void update(int rt, int p, int val){
// 单点修改
// 这个if语句就是判断是否到达叶子结点
if(tree[rt].l == tree[rt].r){
tree[rt].sum = val;
return ;
}
int mid = (tree[rt].l + tree[rt].r) >> 1;
if(p <= mid) update(rt<<1, p, val);
else update(rt<<1|1, p, val);
tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}
*/
void update(int rt, int l, int r, int c){
// 区间修改,同时增加c
if(tree[rt].l >= l && tree[rt].r <= r){
tree[rt].lazy += c; // 记录这个标记
tree[rt].sum += c * (tree[rt].r - tree[rt].l + 1);
return ;
}
down(rt);
int mid = (tree[rt].l + tree[rt].r) >> 1;
if(mid >= r) update(rt<<1, l, r, c);
else if(mid < l) update(rt<<1|1, l, r, c);
else{
update(rt<<1, l, mid, c);
update(rt<<1|1, mid+1, r, c);
}
tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}
/*
int query(int rt, int p){
// 单点查询
if(tree[rt].l == tree[rt].r)
return tree[rt].sum;
int mid = (tree[rt].l + tree[rt].r) >> 1;
// down(rt);
int ans;
if(p <= mid) ans = query(rt<<1, p);
else ans = query(rt<<1|1, p);
return ans;
}
*/
int query(int rt, int l, int r){
// 区间查询
if(tree[rt].l >= l && tree[rt].r <= r)
return tree[rt].sum;
down(rt); // 用到lazy数组
int mid = (tree[rt].l + tree[rt].r) >> 1;
if(r <= mid) return query(rt<<1, l, r);
else if(mid < l) return query(rt<<1|1, l, r);
else
return query(rt<<1, l, mid) + query(rt<<1|1, mid+1, r);
}
int main(){
cin >> n ;
for(int i = 1; i <= n; i++)
cin >> a[i];
build(1, 1, n);
for(int i = 1; i <= 15; i++)
cout << tree[i].sum <<" "<< tree[i].lazy << endl;
cout << query(1, 3, 6) << endl;
return 0;
}