2025/5/2集训
1.线段树
1.1.引入
当一些比较难的区间问题出现时,我们需要线段树.
1.2.概念
线段树 约等于 二叉树
共有\(\log_2(n)\)层,\(2^{(depth+1)}\)个节点(\(depth\)是深度)
1.3.操作
1.3.1.计算信息
合并左儿子和右儿子的信息(所有线段树必备)(叶子节点直接访问就行)
1.3.2.合并(区间加法)
往上一直加就行(顾名思义)
1.4.实现
1.4.1.建树
#include <bits/stdc++.h>
using namespace std;
//线段树
const int maxn = 100010;
int n, m, a[maxn];
struct node{//一个线段树节点
int sum;//区间和
int size;//区间长度
int add;//这段区间被整体加了多少
node(){
sum = size = add = 0;
}
void init(int v){
sum = v;
size = 1;
}
}z[maxn<<2];
#define root 1,n,1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
node operator+(const node &l, const node &r){
node res;
res.sum = l.sum+r.sum;
res.size = l.size+r.size;
return res;
}
void color(int l, int r, int rt, int v){//给l,r,rt节点打一个+v的懒标记
z[rt].add += v;
z[rt].sum += z[rt].size*v;
}
void push_col(int l, int r, int rt){//标记下放,把标记告诉儿子
if (z[rt].add == 0) return;//没标记,不需要下放 (可以不要,但会变慢)
int m = (l+r)>>1;//有标记,需要下放
color(lson, z[rt].add);
color(rson, z[rt].add);
z[rt].add = 0;//下放完了,直接清空
}
void build(int l, int r, int rt){//建树
//用3个数字描述线段树:编号为rt的节点对应区间为l~r
if (l == r){//叶子节点
z[rt].init(a[l]);
return;
}
int m = (l+r)>>1;
build(lson);
build(rson);
//开始合并
z[rt] = z[rt<<1]+z[rt<<1|1];
}
node query(
int l, int r, int rt, //l,r,rt同build
int nowl, int nowr//nowl和nowr表示当前询问的区间
){
if (nowl <= l && r <= nowr) return z[rt];
push_col(l, r, rt);
int m = (l+r)>>1;
if (nowl <= m){
if (m < nowr) return query(lson, nowl, nowr)+query(rson, nowl, nowr);
else return query(lson, nowl, nowr);
}
else return query(rson, nowl, nowr);
}
void modify(int l, int r, int rt, int nowl, int nowr, int v){
//把nowl到nowr全部+=v
if (nowl <= l && r <= nowr){//当前线段树节点被修改区间整体包含
color(l, r, rt, v);
return;
}
push_col(l, r, rt);
int m = (l+r)>>1;
if (nowl <= m) modify(lson, nowl, nowr, v);
if (m < nowr) modify(rson, nowl, nowr, v);
z[rt] = z[rt<<1]+z[rt<<1|1];
}
int main(){
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
build(root);
cin >> m;
for (int i = 1; i <= m; i++){
int opt;
cin >> opt;
if (opt == 1){//询问
int l, r;
cin >> l >> r;
node answ = query(root, l, r);
cout << answ.sum << '\n';
}
else if (opt == 2){//修改(把l~r全+=v)
int l, r, v;
cin >> l >> r >> v;
modify(root, l, r, v);
}
}
return 0;
}
浙公网安备 33010602011771号