线段树基本操作(1)

线段树基本操作(1)

(建树,查询和单点修改)

用途

  • 线段树可以快速的对一段区间进行操作,包括求区间最值,并在对某点修改后再次求区间最值,对一个区间上的所有点进行修改
  • 不需要对区间上的元素进行循环,而是一种类似于二分,分治的思想

方法

  1. 把一段长度为2^k的区间逐次对半分,可以总共分成2^(k+1)-1各节点,变成了一棵二叉树
  2. 对于区间[lt, rt],它的子节点为区间[lt, mid]和区间[mid+1, rt]
  3. 查询时只要要查询的区间的左右边界刚好等于已知区间的边界,就可以返回值了,不需要一搜到底
  4. 对于单点修改,基本上和二分查找差不多(查找时查找的值是该点的下标)
//线段树 
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 10000 + 10;
int n;
int val[2*MAXN], p[MAXN];

void build(int node, int lt, int rt)     //建树 
{
    if(lt == rt) {val[node] = p[lt]; return ;}

    int mid = (lt + rt) >> 1;

    build(node*2, lt, mid); build(node*2+1, mid+1, rt);
    val[node] = min(val[node*2], val[node*2+1]);

    return ;
}

int query(int node, int lt, int rt, int ll, int rr)   //区间查询 
//lt, rt:点node的左右区间  ll, rr:要查的左右区间
{
    if(lt == ll && rt == rr) return val[node];

    int mid = (lt + rt) >> 1;

    if(rr <= mid) return query(node*2, lt, mid, ll, rr);
    if(ll > mid) return query(node*2+1, mid+1, rt, ll, rr);

    int v1 = query(node*2, lt, mid, ll, mid);
    int v2 = query(node*2+1, mid+1, rt, mid+1, rr);
    return min(v1, v2);
} 
// 使用条件:相邻的区间的信息可以被合并成两个区间的并区间的信息

void change(int node, int lt, int rt, int u, int add)  //单点修改 
//u要修改的值的下标,add要给修改的值加上的值
{
    if(lt == rt) {val[node] += add; return ;}

    int mid = (lt + rt) >> 1;
    if(u <= mid) change(node*2, lt, mid, u, add);
    if(u > mid) change(node*2+1, mid+1, rt, u, add);

    val[node] = min(val[node*2], val[node*2+1]);   //回溯修改 
 } 

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++)
        cin >> p[i];

    build(1, 1, n);

//  int l, r;
//  cin >> l >> r;
//  cout << query(1, 1, n, l, r);

    int u, d;
    cin >> u >> d;
    change(1, 1, n, u, d);
    cout << query(1, 1, n, 2, 4);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值